diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9f663b5d4243a465a38b5ebcb6efabd29d48684f
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,26 @@
+version: 2.1 # use CircleCI 2.1
+orbs:
+  browser-tools: circleci/browser-tools@1.2.4
+jobs: # a collection of steps
+  build: # runs not using Workflows must have a `build` job as entry point
+
+    working_directory: ~/faidare # directory where steps will run
+
+    docker: # run the steps with Docker
+      - image: cimg/openjdk:11.0-browsers # ...with this image as the primary container; this is where all `steps` will run
+      - image: docker.elastic.co/elasticsearch/elasticsearch:7.13.2
+        name: elasticsearch
+        environment:
+          transport.host: localhost
+          network.host: elasticsearch
+          http.port: 9200
+          cluster.name: es-cluster
+          discovery.type: single-node
+          xpack.security.enabled: false
+          ES_JAVA_OPTS: -Xms750m -Xmx750m
+
+    steps: # a collection of executable commands
+      - browser-tools/install-chrome
+      # check out source code to working directory
+      - checkout
+      - run: ./gradlew check build
diff --git a/.dockerignore b/.dockerignore
index 5d29e4d09169e7a68278007eb96c999693595ea2..103b03dbdb0dcf1bd1e7788a90e311ccf6cf887c 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,5 +1,3 @@
 .git/
-frontend/node_modules/
 backend/out
-frontend/.gradle
 .gradle/
diff --git a/.github/renovate.json5 b/.github/renovate.json5
new file mode 100644
index 0000000000000000000000000000000000000000..de01b8ea730d971cd3866a66a891284ac7262401
--- /dev/null
+++ b/.github/renovate.json5
@@ -0,0 +1,34 @@
+{
+  "extends": [
+    "config:base"
+  ],
+  "enabledManagers": [
+    "npm"
+  ],
+  // target chore/next branch
+  "baseBranches": [
+    "chore/next"
+  ],
+  // only 1 PR at the same time (to avoid cascading rebase)
+  "prConcurrentLimit": 1,
+  // auto-merge if build is OK
+  "automerge": true,
+  "packageRules": [
+    // group all minor dependencies, once a week
+    {
+      "matchPackagePatterns": [
+        "*"
+      ],
+      "matchUpdateTypes": [
+        "minor",
+        "patch"
+      ],
+      "matchCurrentVersion": ">=1",
+      "groupName": "all non-major dependencies",
+      "groupSlug": "all-minor-patch",
+      "schedule": [
+        "after 1am on Thursday"
+      ]
+    }
+  ]
+}
diff --git a/.gitignore b/.gitignore
index 0648667bdb50f03dbf8151eff52f71c863b4bcf7..fb05eb97d89ae06fd086c9e782420570935b3c89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,43 +95,11 @@ local.properties
 *.ipr
 
 # User-specific stuff
-.idea/*
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# Generated files
-.idea/**/contentModel.xml
-
-# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
-
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
-
-# Gradle and Maven with auto-import
-# When using Gradle or Maven with auto-import, you should exclude module files,
-# since they will be recreated, and may cause churn.  Uncomment if using
-# auto-import.
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
+.idea
 
 # CMake
 cmake-build-*/
 
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
 # File-based project format
 *.iws
 
@@ -144,21 +112,12 @@ out/
 # JIRA plugin
 atlassian-ide-plugin.xml
 
-# Cursive Clojure plugin
-.idea/replstate.xml
-
 # Crashlytics plugin (for Android Studio and IntelliJ)
 com_crashlytics_export_strings.xml
 crashlytics.properties
 crashlytics-build.properties
 fabric.properties
 
-# Editor-based Rest Client
-.idea/httpRequests
-
-# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
-
 ### Intellij Patch ###
 # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
 
@@ -167,9 +126,6 @@ fabric.properties
 # .idea/misc.xml
 # *.ipr
 
-# Sonarlint plugin
-.idea/sonarlint
-
 ### Kotlin ###
 # Compiled class file
 *.class
@@ -269,4 +225,4 @@ gradle-app.setting
 **/build/
 
 # End of https://www.gitignore.io/api/gradle,eclipse,intellij,visualstudiocode,kotlin,git,macos,linux
-frontend/package-lock.json
+/web/node_modules/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1886bc3ede64681e6c5358756950c5c2dd95c714..452d82424f2d796c1aa24e407d523ec83c0f97e7 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,11 +18,11 @@ image: registry.forgemia.inra.fr/urgi-is/docker-rare/docker-browsers:latest
 variables:
   GRADLE_OPTS: "-Dorg.gradle.daemon=false"
   GRADLE_USER_HOME: $CI_PROJECT_DIR/.gradle
-  APP_NAME: faidare
-  JAR_PATH: "backend/build/libs/${APP_NAME}.jar"
+  SERVICE_NAME: faidare-cards
+  JAR_PATH: "backend/build/libs/faidare.jar"
   GIT_DEPTH: 0
   IMAGE_TAG: $CI_COMMIT_REF_SLUG
-  ELASTIC_VERSION: "6.6.2"
+  ELASTIC_VERSION: "7.13.2"
   DOCKER_OPTS: "--mtu=1450"
 
 # Gradle cache for all jobs
@@ -30,52 +30,35 @@ cache:
   key: "$CI_COMMIT_REF_NAME"
   paths:
     - ".gradle"
-    - "frontend/.gradle/"
-    - "frontend/node_modules/"
 
 # PRE-BUILD
 
 build-loader-docker-image:
- image: registry.forgemia.inra.fr/urgi-is/docker-rare/docker-git:latest
- stage: pre-build
- services:
-  - docker:20.10.6-dind
- script:
-  # build the image
-  - docker build -t registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:${IMAGE_TAG} .
-  - docker build -t registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:latest .
-  # Login before pushing the image
-  - docker login registry.forgemia.inra.fr -u $CONTAINER_REGISTRY_USERNAME -p $CONTAINER_REGISTRY_TOKEN
-  # push the built image
-  - docker push registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:${IMAGE_TAG}
-  # only push latest tag on master branch
-  - if [ "master" == "${CI_COMMIT_REF_SLUG}" ] ; then docker push registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:latest ; fi;
- only:
-  changes:
-   - scripts/*
-   - backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/*_mapping.json
-   - backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json
-   - .gitlab-ci.yml
- allow_failure: true
-
+  image: registry.forgemia.inra.fr/urgi-is/docker-rare/docker-git:latest
+  stage: pre-build
+  services:
+    - docker:20.10.6-dind
+  script:
+    # build the image
+    - docker build -t registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:${IMAGE_TAG} .
+    - docker build -t registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:latest .
+    # Login before pushing the image
+    - docker login registry.forgemia.inra.fr -u $CONTAINER_REGISTRY_USERNAME -p $CONTAINER_REGISTRY_TOKEN
+    # push the built image
+    - docker push registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:${IMAGE_TAG}
+    # only push latest tag on master branch
+    - if [ "${CI_DEFAULT_BRANCH}" == "${CI_COMMIT_REF_SLUG}" ] ; then docker push registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:latest ; fi;
+  rules:
+    - changes:
+      - Dockerfile
+      - scripts/*
+      - backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/*_mapping.json
+      - backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json
+      - .gitlab-ci.yml
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+  allow_failure: true
 
 # TESTS
-
-
-lint:
-  stage: test
-  tags:
-    - openstack
-  script: "./gradlew lint"
-  cache:
-    key: "$CI_COMMIT_REF_NAME"
-    policy: pull
-    paths:
-      - ".gradle"
-      - "frontend/.gradle/"
-      - "frontend/node_modules/"
-
-
 test-and-sonarqube:
   stage: test
   tags:
@@ -99,40 +82,28 @@ test-and-sonarqube:
     GRADLE_OPTS: "-Dorg.gradle.daemon=true"
     SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
     GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
+    ES_JAVA_OPTS: "-Xms2g -Xmx2g"
   cache:
     key: "${CI_COMMIT_REF_NAME}"
     policy: pull-push
     paths:
       - ".gradle"
-      - "frontend/.gradle/"
-      - "frontend/node_modules/"
       - .sonar/cache
   script:
-    - ./gradlew :frontend:assemble --parallel
-    - ./gradlew :backend:test jacocoTestReport --parallel
-    - find /tmp/node/*/bin -name node -exec ln -s {} /tmp/node/node \;
-    - export PATH="/tmp/node/:$PATH"
+    - ./gradlew test jacocoTestReport --parallel
+    # disable sonarqube because it apparently needs node, but I don't know why, and it can't find it anymore now that
+    # there is no frontend project anymore, and it takes sooooo much time to complete anyway for results that nobody
+    # will ever look
     - ./gradlew -s sonarqube -x test --parallel
   artifacts:
     reports:
       junit:
         - ./backend/build/test-results/test/TEST-*.xml
-        # - ./frontend/karma-junit-tests-report/TEST*.xml
-  only:
-    refs:
-      - merge_requests
-
-
-test-and-sonarqube-master:
-  extends: test-and-sonarqube
-  only:
-    refs:
-      - master
-
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+  interruptible: true
 
 # BUILD
-
-
 build:
   tags:
     - openstack
@@ -144,15 +115,22 @@ build:
     policy: pull
     paths:
       - ".gradle"
-      - "frontend/.gradle/"
-      - "frontend/node_modules/"
   artifacts:
     paths:
       - "$JAR_PATH"
     expire_in: 1 week
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /SKIP_DEPLOY/i
+      when: never
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+  interruptible: true
 
-
-.restart-config-server: &restart_config_server
+restart-config-server-openstack:
+  tags:
+    - openstack
+  variables:
+    SERVER_IP: ${SERVER_IP_OPENSTACK_DEV}
+    SERVER_USER: ${SERVER_USER_OPENSTACK}
   stage: build
   script:
     - eval $(ssh-agent -s)
@@ -161,28 +139,17 @@ build:
     - ssh ${SERVER_USER}@${SERVER_IP} "sudo systemctl restart bootapp@config-server"
     - eval $(ssh-agent -k)
   allow_failure: true
-
-restart-config-server-proxmox:
-  variables:
-    SERVER_IP: ${SERVER_IP_PROXMOX}
-    SERVER_USER: ${SERVER_USER_PROXMOX}
-  <<: *restart_config_server
-
-restart-config-server-openstack:
-  tags:
-    - openstack
-  variables:
-    SERVER_IP: ${SERVER_IP_OPENSTACK_DEV}
-    SERVER_USER: ${SERVER_USER_OPENSTACK}
-  <<: *restart_config_server
-
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /SKIP_DEPLOY/i
+      when: never
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
 
 # DEPLOY
-
-
-.deploy-to-vm: &deploy_to_vm
+.deploy-to-vm:
   # Hidden job which serves as template for executed jobs below.
   # See https://docs.gitlab.com/ee/ci/yaml/#anchors
+  tags:
+   - openstack
   retry: 2
   script:
     ## SSH initialization
@@ -190,22 +157,19 @@ restart-config-server-openstack:
     - ssh-add <(echo "${SSH_PRIVATE_KEY}")
     - ssh -o StrictHostKeyChecking=no ${SERVER_USER}@${SERVER_IP} 'echo "Successfully connected on $(hostname)"'
     # Copy jar
-    - scp ./backend/build/libs/${APP_NAME}.jar ${SERVER_USER}@${SERVER_IP}:/tmp/${APP_NAME}-${ENV}.jar
-    - ssh ${SERVER_USER}@${SERVER_IP} "sudo mv /tmp/${APP_NAME}-${ENV}.jar /opt/bootapp/${APP_NAME}-${ENV}.jar ; sudo chown -R bootapp:bootapp /opt/bootapp/"
-    # Restarting service with the updated jar and the according Spring profiles enabled
-    - ssh ${SERVER_USER}@${SERVER_IP} "sudo systemctl restart bootapp@${APP_NAME}-${ENV}"
+    - scp ${JAR_PATH} ${SERVER_USER}@${SERVER_IP}:/tmp/${SERVICE_NAME}-${ENV}.jar
+    - ssh ${SERVER_USER}@${SERVER_IP} "sudo mv /tmp/${SERVICE_NAME}-${ENV}.jar /opt/bootapp/ ; sudo chown -R bootapp:bootapp /opt/bootapp/ ; sudo systemctl restart bootapp@${SERVICE_NAME}-${ENV}"
     - eval $(ssh-agent -k)
     - echo "Deploy done. Application should be available at http://${SERVER_IP}:${APP_PORT}/${CONTEXT_PATH}"
-  only:
-    changes:
+  rules:
+    - changes:
       - .gitlab-ci.yml
       - backend/src/**/*
-      - frontend/**/*
   allow_failure: false
+  interruptible: false
+  needs: ["build"]
 
 deploy-to-beta:
-  tags:
-   - openstack
   stage: deploy-beta
   extends: .deploy-to-vm
   variables:
@@ -213,78 +177,69 @@ deploy-to-beta:
     SERVER_IP: ${SERVER_IP_OPENSTACK_DEV}
     APP_PORT: ${BETA_FAIDARE_PORT}
     ENV: beta
-    CONTEXT_PATH: faidare-beta
-  except:
-    refs:
-      - master
-  only:
-    refs:
-      - branches
-  when: always
+    CONTEXT_PATH: faidare
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /SKIP_DEPLOY/i
+      when: never
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+      when: always
 
-deploy-to-staging:
-  tags:
-   - openstack
+deploy-to-staging-public:
   stage: deploy-staging
   extends: .deploy-to-vm
   variables:
     SERVER_USER: ${SERVER_USER_OPENSTACK}
     SERVER_IP: ${SERVER_IP_OPENSTACK_DEV}
-    APP_PORT: ${STAGING_FAIDARE_PORT}
-    ENV: staging
-    CONTEXT_PATH: faidare-staging
-  only:
-    refs:
-      - branches
-  except:
-    refs:
-      - master
-  when: manual
+    APP_PORT: ${STAGING_PUBLIC_FAIDARE_PORT}
+    ENV: staging-public
+    CONTEXT_PATH: faidare
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /SKIP_DEPLOY/i
+      when: never
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+      when: manual
 
-deploy-to-int:
-  tags:
-   - proxmox
-  stage: deploy-production
+deploy-to-staging-private:
+  stage: deploy-staging
   extends: .deploy-to-vm
   variables:
-    SERVER_USER: ${SERVER_USER_PROXMOX}
-    SERVER_IP: ${SERVER_IP_PROXMOX}
-    APP_PORT: ${INT_FAIDARE_PORT}
-    ENV: int
-    CONTEXT_PATH: faidare-int
-  only:
-    refs:
-      - master
-  when: manual
+    SERVER_USER: ${SERVER_USER_OPENSTACK}
+    SERVER_IP: ${SERVER_IP_OPENSTACK_DEV}
+    APP_PORT: ${STAGING_PRIVATE_FAIDARE_PORT}
+    ENV: staging-private
+    CONTEXT_PATH: faidare-private
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /SKIP_DEPLOY/i
+      when: never
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+      when: manual
 
 deploy-to-prod-public:
-  tags:
-   - proxmox
   stage: deploy-production
   extends: .deploy-to-vm
   variables:
-    SERVER_USER: ${SERVER_USER_PROXMOX}
-    SERVER_IP: ${SERVER_IP_PROXMOX}
+    SERVER_USER: ${SERVER_USER_OPENSTACK}
+    SERVER_IP: ${SERVER_IP_OPENSTACK_PROD}
     APP_PORT: ${PROD_PUBLIC_FAIDARE_PORT}
     ENV: prod-public
     CONTEXT_PATH: faidare
-  only:
-    refs:
-      - master
-  when: manual
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /SKIP_DEPLOY/i
+      when: never
+    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+      when: manual
 
 deploy-to-prod-private:
-  tags:
-   - proxmox
   stage: deploy-production
   extends: .deploy-to-vm
   variables:
-    SERVER_USER: ${SERVER_USER_PROXMOX}
-    SERVER_IP: ${SERVER_IP_PROXMOX}
+    SERVER_USER: ${SERVER_USER_OPENSTACK}
+    SERVER_IP: ${SERVER_IP_OPENSTACK_PROD}
     APP_PORT: ${PROD_PRIVATE_FAIDARE_PORT}
     ENV: prod-private
     CONTEXT_PATH: faidare-private
-  only:
-    refs:
-      - master
-  when: manual
+  rules:
+    - if: $CI_COMMIT_MESSAGE =~ /SKIP_DEPLOY/i
+      when: never
+    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+      when: manual
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index ca99a00edbda7ccc394869431fec04f9a5ac33a6..0000000000000000000000000000000000000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <annotationProcessing>
-      <profile name="Gradle Imported" enabled="true">
-        <outputRelativeToContentRoot value="true" />
-        <processorPath useClasspath="false">
-          <entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-configuration-processor/2.1.2.RELEASE/db9671c321defb942a6700fae8a7700a137a25e/spring-boot-configuration-processor-2.1.2.RELEASE.jar" />
-        </processorPath>
-        <module name="faidare.backend.main" />
-      </profile>
-    </annotationProcessing>
-    <bytecodeTargetLevel target="1.8" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 15a15b218a29e09c9190992732698d646e4d659a..0000000000000000000000000000000000000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="Encoding" addBOMForNewFiles="with NO BOM" />
-</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index ff8249e49968d1849269b0d8a2fe49a31c72a63f..0000000000000000000000000000000000000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="FrameworkDetectionExcludesConfiguration">
-    <file type="web" url="file://$PROJECT_DIR$" />
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/out" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 3b2a562bc3214c46382cc1761196d85196a94d66..0000000000000000000000000000000000000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/faidare.iml" filepath="$PROJECT_DIR$/.idea/modules/faidare.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/backend/faidare.backend.iml" filepath="$PROJECT_DIR$/.idea/modules/backend/faidare.backend.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/backend/faidare.backend.main.iml" filepath="$PROJECT_DIR$/.idea/modules/backend/faidare.backend.main.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/backend/faidare.backend.test.iml" filepath="$PROJECT_DIR$/.idea/modules/backend/faidare.backend.test.iml" />
-      <module fileurl="file://$PROJECT_DIR$/.idea/modules/frontend/faidare.frontend.iml" filepath="$PROJECT_DIR$/.idea/modules/frontend/faidare.frontend.iml" />
-      <module fileurl="file://$PROJECT_DIR$/backend/src/main/main.iml" filepath="$PROJECT_DIR$/backend/src/main/main.iml" />
-      <module fileurl="file://$PROJECT_DIR$/backend/src/test/test.iml" filepath="$PROJECT_DIR$/backend/src/test/test.iml" />
-    </modules>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7f4cb416c083d265558da75d457237d671..0000000000000000000000000000000000000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$" vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.secrets.baseline b/.secrets.baseline
index 58672400dda7618e0fea2e3886828061441b2b73..46d11502408f9906c3d1fbec2ae9ae30afaefb76 100644
--- a/.secrets.baseline
+++ b/.secrets.baseline
@@ -3,7 +3,7 @@
     "files": "frontend/package-lock.json|^.secrets.baseline$",
     "lines": null
   },
-  "generated_at": "2021-08-02T15:23:45Z",
+  "generated_at": "2021-10-01T17:08:35Z",
   "plugins_used": [
     {
       "name": "AWSKeyDetector"
@@ -58,14 +58,14 @@
         "hashed_secret": "dd447c7c799dd4ebaacca8f0ad3da45a097d7211",
         "is_secret": false,
         "is_verified": false,
-        "line_number": 228,
+        "line_number": 204,
         "type": "Base64 High Entropy String"
       },
       {
         "hashed_secret": "8074db38f8a8acec1a147bc5daf2799ff6693fff",
         "is_secret": false,
         "is_verified": false,
-        "line_number": 247,
+        "line_number": 248,
         "type": "Base64 High Entropy String"
       }
     ],
@@ -412,15 +412,6 @@
         "type": "Base64 High Entropy String"
       }
     ],
-    "backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentSearchCriteria.java": [
-      {
-        "hashed_secret": "115a9779753641744ba0e30c3ff8586c823b6f7e",
-        "is_secret": false,
-        "is_verified": false,
-        "line_number": 18,
-        "type": "Base64 High Entropy String"
-      }
-    ],
     "backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/query/impl/ESGenericQueryFactory.java": [
       {
         "hashed_secret": "084c833a01fb1d770f994aaec6a07f282e41827a",
@@ -2552,6 +2543,22 @@
         "type": "Base64 High Entropy String"
       }
     ],
+    "gradle.properties": [
+      {
+        "hashed_secret": "93220646d2e029229894cf6f9e5d170c8fc59dbb",
+        "is_secret": true,
+        "is_verified": false,
+        "line_number": 5,
+        "type": "Base64 High Entropy String"
+      },
+      {
+        "hashed_secret": "93220646d2e029229894cf6f9e5d170c8fc59dbb",
+        "is_secret": true,
+        "is_verified": false,
+        "line_number": 5,
+        "type": "Hex High Entropy String"
+      }
+    ],
     "scripts/harvest.sh": [
       {
         "hashed_secret": "9b4ea0964706f977148ec989e7373d9622613547",
diff --git a/ABOUT.md b/ABOUT.md
deleted file mode 120000
index 417bbb999586f128c5482545666bc64117e4c9c0..0000000000000000000000000000000000000000
--- a/ABOUT.md
+++ /dev/null
@@ -1 +0,0 @@
-frontend/src/assets/faidare/ABOUT.md
\ No newline at end of file
diff --git a/ABOUT.md b/ABOUT.md
new file mode 100644
index 0000000000000000000000000000000000000000..3153002be6f3231e3423893f3d91c88ef332e8a1
--- /dev/null
+++ b/ABOUT.md
@@ -0,0 +1,13 @@
+# About this data portal
+
+The purpose of this portal is to facilitate the discoverability of public data on plant biology from a federation of established data repositories.
+
+It is based on the [Breeding API (BrAPI)](https://brapi.org/) specifications and facilitates the access to genotype and phenotype datasets for crop and forest plants through an easy to use web interface.
+It also provides a standard interface that can be accessed programatically through [web services](https://urgi.versailles.inrae.fr/faidare/swagger-ui.html).
+
+It is an extension of the generic [Data-Discovery portal](https://forgemia.inra.fr/urgi-is/data-discovery), a web portal that allows finding any type of data across several databases through a lightweight keyword based search.
+FAIDARE offers more detailed search and data retrieval capabilities and it takes advantage of the growing adoption of the BrAPI.
+
+It has been developed by [INRAE-URGI](http://urgi.versailles.inrae.fr/) in collaboration with [**Elixir Plant**](https://elixir-europe.org/communities/plant-sciences), [**Phenome-Emphasis.fr**](https://www.phenome-emphasis.fr/phenome_eng/Methodological-projects/MCP2-Distributed-Information-system) and [**Elixir-fr/IFB**](https://www.france-bioinformatique.fr).
+
+If you want to join the FAIDARE federation, please read the "Join us" section and [contact us](mailto:urgi-contact@inrae.fr?subject=%5BFAIDARE%5D).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d3127cc00020b10efa9c72a5bdda1b5653976e3c..d760ec6adacfe12bb2a75e792815543c496d1546 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -57,8 +57,8 @@
 * Look at the [README.md](README.md) for installation and execution instructions.
 * Recommanded IDE is [Intellij IDEA](https://www.jetbrains.com/idea/)
 * Use linting to apply code standards within the team:
-  * Use `ng lint` (for frontend code only)
-  * Use [Checkstyle](https://checkstyle.org/) and [PMD](https://pmd.github.io/) (**TODO**: implement) for backend (+frontend?) code
+  * Use `yarn format` (for `web` code only)
+  * Use [Checkstyle](https://checkstyle.org/) and [PMD](https://pmd.github.io/) (**TODO**: implement) for backend code
 * All runtime variables should be externalized from the code in order to facilitate the CI management (database host/port, application name, public URL, JSON location...) and the adoption by partners
 * Configure [Yelp's detect-secrets](https://github.com/Yelp/detect-secrets) pre-commit hook to track any high entropy strings, which could possibly be leaked secrets.
   * Run: `pip3 install pre-commit detect-secrets --user && pre-commit install` to configure you dev environment.
diff --git a/Dockerfile b/Dockerfile
index d9b28b366813c26130f7cfbbc39bd3bf9eb3e172..75b15021ab79c72735bec70dc527e7c2c3708269 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,6 +2,7 @@ FROM alpine
 LABEL Author="Raphaël FLORES <raphael.flores@inrae.fr>"
 
 COPY scripts/harvest.sh /opt/scripts/
+COPY scripts/to_bulk.jq /opt/scripts/
 
 # COPY dao settings
 COPY backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json /opt/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json
diff --git a/HELP.md b/HELP.md
deleted file mode 120000
index 7862492f7086bd00ffce4b9e5949fa293e24eafa..0000000000000000000000000000000000000000
--- a/HELP.md
+++ /dev/null
@@ -1 +0,0 @@
-frontend/src/assets/faidare/HELP.md
\ No newline at end of file
diff --git a/HELP.md b/HELP.md
new file mode 100644
index 0000000000000000000000000000000000000000..d6240d00a17de2c066722365acfc19c01c23d1e7
--- /dev/null
+++ b/HELP.md
@@ -0,0 +1,17 @@
+# Help section
+
+> Note: this application is responsive, meaning that its rendering will adapt to the screen's size of your device, hence location of items below can be different than stated.
+
+You can find data by building your own query using the fields available in the two tabs of the form:
+* The `Germplasm` tab allow you to add criteria on plant material/germplasm (_e.g._ its name, genus or species).
+* The `Trait` tab allow you to add criteria on trait(s) and/or variable(s) name(s).
+
+In each field, one or several term(s) can be entered.
+As you begin to type, a list of relevant suggestions is proposed to guide you in your search.
+
+The query is launched as soon as at least one parameter is selected in the form.
+The results are automatically updated if a parameter is added or removed.
+
+To refine your search, you can add more specific filters by using the facets/categories on the left side.
+> Note: applying several filters in the same facet/category will search for documents related to any of the selected terms (resulting in a `OR` operator between all the category's terms).
+> In contrary, applying filters in different facets/categories will search for documents having both filters (resulting in an `AND` operator for the different facets).
diff --git a/HOW-TO-JOIN.md b/HOW-TO-JOIN.md
deleted file mode 120000
index 42501082c7ddbaf3942b86d8f4876cf4e9f9b077..0000000000000000000000000000000000000000
--- a/HOW-TO-JOIN.md
+++ /dev/null
@@ -1 +0,0 @@
-frontend/src/assets/faidare/HOW-TO-JOIN.md
\ No newline at end of file
diff --git a/HOW-TO-JOIN.md b/HOW-TO-JOIN.md
new file mode 100644
index 0000000000000000000000000000000000000000..4c9843e23b05a35cced150e06f38d1260509cb80
--- /dev/null
+++ b/HOW-TO-JOIN.md
@@ -0,0 +1,66 @@
+# How to join FAIDARE federation?
+
+If you want your information system to be part of the FAIDARE federation, we invite you to [contact us](mailto:urgi-contact@inra.fr?subject=%5BFAIDARE%5D) as soon as possible so that we can follow your progress and assist you if needed.
+
+You will need to create a new `source` corresponding to your information system.
+For this, you will have to set up your own [BrAPI](https://brapi.org/) endpoint and reference it in the sources of [Elixir's FAIDARE harvester](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis).
+
+General information and considerations can be found on the [Elixir Plant](https://elixir-europe.org/communities/plant-sciences) web page.
+
+## Creation of a BrAPI endpoint
+To create a new endpoint, you should implement the BrAPI calls needed to give access to the data of your information system.
+Those calls are documented in various formats on the [Developer resources](https://www.brapi.org/developers#) section of the BrAPI web site.
+
+The BrAPI calls currently used by FAIDARE are:
+* germplasm
+* location
+* ontology
+* program
+* study
+* study/{studyDbId}/observationVariable
+* study/{studyDbId}/germplasm
+* study/{studyDbId}/observationUnit (can be resource intensive and therefore not implemented)
+* trial
+
+> Note that since the tool makes a backlink to your information system, we need a URL in the `DocumentationURL` field of the BrAPI for researchers to get more detailed information about the indexed entry directly in your information system.
+
+To ensure the quality of your BrAPI endpoint, you can use the validation tools provided by the BrAPI community, especially [Brava](http://webapps.ipk-gatersleben.de/brapivalidator/).
+
+If you have any question or need help implementing BrAPI calls, you can [contact the BrAPI community](https://brapi.org/).
+
+## Referencement of a BrAPI endpoint
+For your endpoint to be visible on FAIDARE, you have to declare it in the sources of [Elixir's FAIDARE harvester](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis).
+To do this, you only have to create your own configuration file, according to the following template, and add it to the [`sources`](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis/tree/master/sources) directory of the harvester:
+```
+{
+  "@context": {
+    "schema": "http://schema.org/",
+    "brapi": "https://brapi.org/"
+  },
+  "@type": "schema:DataCatalog",
+  "@id": "[information system URL]",
+  "schema:identifier": "[BrAPI endpoint name]",
+  "schema:name": "[information system name]",
+  "brapi:endpointUrl": "[BrAPI endpoint URL]"
+}
+```
+Example: [URGI.json](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis/blob/master/sources/URGI.json)
+```
+{
+  "@context": {
+    "schema": "http://schema.org/",
+    "brapi": "https://brapi.org/"
+  },
+  "@type": "schema:DataCatalog",
+  "@id": "https://urgi.versailles.inra.fr/gnpis",
+  "schema:identifier": "URGI",
+  "schema:name": "URGI GnpIS",
+  "brapi:endpointUrl": "https://urgi.versailles.inra.fr/faidare/brapi/v1/"
+}
+```
+
+If you have any question or need help referencing your endpoint, you can [contact us](mailto:urgi-contact@inra.fr?subject=%5BFAIDARE%5D).
+
+## Data availability & update
+[Elixir's FAIDARE harvester](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis) extract the metadata available from all declared sources (_i.e._ BrAPI endpoint) and index it into a centralised Elasticsearch cache.
+The sources are reindexed regularly (once a month maximum) but if you want a reindexation following a major update on your side, please [inform us](mailto:urgi-contact@inra.fr?subject=%5BFAIDARE%5D).
diff --git a/LEGAL-MENTIONS.md b/LEGAL-MENTIONS.md
deleted file mode 120000
index 47b69b15b9ff400f64697ecad006914633d77871..0000000000000000000000000000000000000000
--- a/LEGAL-MENTIONS.md
+++ /dev/null
@@ -1 +0,0 @@
-frontend/src/assets/faidare/LEGAL-MENTIONS.md
\ No newline at end of file
diff --git a/LEGAL-MENTIONS.md b/LEGAL-MENTIONS.md
new file mode 100644
index 0000000000000000000000000000000000000000..21aa25f5359596345684b6786ca40e46de74b8ca
--- /dev/null
+++ b/LEGAL-MENTIONS.md
@@ -0,0 +1,51 @@
+# General Terms of Use
+
+By browsing this web site, you acknowledge and accept its general terms of use described below.
+
+## Intellectual property
+
+Except where otherwise noted, content on this site is licensed under a [Creative Commons Attribution 4.0 International license](https://creativecommons.org/licenses/by/4.0/).
+
+The logo is the property of INRAE and you are not allowed to re-use it for your own work and purpose.
+
+## Content
+
+The portal is maintained by URGI, an INRAE unit, and its [Data Management Plan (DOI: 10.15454/9HM5UI)](https://doi.org/10.15454/9HM5UI) has been defined in the frame of the [Plant Bioinformatics Facility (PlantBioinfoPF, DOI: 10.15454/1.5572414581735654E12)](https://doi.org/10.15454/1.5572414581735654E12) that hosts the portal.
+
+Access to this web site can be interrupted at any time and without prior warning in case of force majeure.
+In case of a planned service interruption, users will be notified in advance by the editor as far as possible.
+
+The portal allows to find public data across a federation of databases.
+The licences associated to data are therefore defined by the institutes in charge of them.
+
+The portal links to external web sites.
+INRAE does not take responsibility of the content of these web site.
+
+Users are sole responsible for the searches they carry out, as well as for the interpretation and for the use they make of the results.
+
+Users are informed that their use of the results should not infringe on current legislation or the recommendations of the French Data Protection Authority (CNIL) with respect to personal data.
+Users are warned that the information must be used for strictly professional purposes only and downloading screen shots in order to constitute or enrich a database is contrary to French law and therefore forbidden, as is its use for commercial or advertising purposes (CNIL).
+
+The portal may give access to personal and professional data concerning technical and scientific actors in relation with the data.
+This information helps to identify and acknowledge the authors of the scientific works.
+This personal information is attached to the produced datasets and follows the data life cycle.
+ 
+## Personal data
+
+Technical data (date, hour, IP address of the computer of the visitor, pages viewed) are collected only for the statistical analysis of the usage of the portal.
+These data are kept confidential and not transmitted to any other party.
+They are stored on INRA’s private servers for 5 years.
+
+During visits on URGI web site and its hosted applications, a cookie can be automatically installed on visitor’s web browsers to retrieve statistics on the pages that are visited and support improvements of the services provided by the web site.
+Visitors can configure their web browsers in order to be informed of the setting of cookies and refuse them.
+
+According to the European Regulation on the protection of personal data (EU Regulation 2016/679), you have the right to access, rectify, oppose and delete information about yourself.
+If you wish to exercise this right and obtain information about yourself, please contact us:
+- By [email](mailto:urgi-contact@inra.fr?subject=%5BData%20Discovery%5D%20GPDR%20request)
+- Or via any other way available on our [contact form](https://urgi.versailles.inra.fr/Contact-us)
+
+## Modifications
+
+The editor might change the terms of use and user’s rights without prior warning.
+
+Last update: 2021 February 22th
diff --git a/README.md b/README.md
index 028a48c73e8654e923592c7be5a691cf9ffb35ca..f49182dcc156aff02c7d0fd22c3bef276dbf6570 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 # FAIDARE: FAIR Data-finder for Agronomic Research
-This application provides web services (based on the BrAPI standard) and a web interface with easy to use filters to facilitates the access to plant datasets from a federation of sources.
+This application provides web services (based on the BrAPI standard) and a web interface with easy to use filters to facilitate the access to plant datasets from a federation of sources.
 
 [[_TOC_]]
 
@@ -9,34 +9,28 @@ Look at the [contribution guide](CONTRIBUTING.md).
 
 ## Install development environment
 
-- Install `node` and `npm`
+- Install `node` and `yarn`
 
 Installation via `nvm` is recommended for easier control of installed version:
 https://github.com/creationix/nvm
 
 ```sh
-nvm install 10.13.0
-nvm use v10.13.0
-```
-
-- Install Angular CLI
-
-```sh
-npm install -g @angular/cli@7.0.6
+nvm install 16.14.0
+nvm use v16.14.0
 ```
 
 - Install JS dependencies
 
 ```sh
-cd frontend
-npm install
+cd web
+yarn
 ```
 
 - Install latest Java JDK8
 
 See latest instructions for your operating system.
 
-- (Optional) Install `docker` and `docker-compose`
+- (Optional) Install `docker`
 
 If you want to run an Elasticsearch and Kibana instance on your machine.
 You can use your favorite package manager for that
@@ -49,7 +43,7 @@ First make sure you have access to an Elasticsearch HTTP API server on `http://1
 If you want to run an Elasticsearch server on your development machine you can use the `docker`/`docker-compose` configuration like so:
 
 ```sh
-docker-compose up
+docker compose up
 ```
 
 > This will launch an Elasticsearch server (with port forwarding `9200`) and a Kibana server (with port forwarding `5601`)
@@ -57,13 +51,20 @@ docker-compose up
 > **Warning**: This repository does not automatically index data into Elasticsearch, you need to prepare your indices beforehand.
 
 
-If you just need access to API (to run the `ng serve` on top of it), you can run:
+If you just need access to API, you can run:
 
 ```sh
 ./gradlew bootRun
 ```
 
-Otherwise, for the complete server (backend APIs + frontend interface), you can run:
+If you are developing and need to work on the `web` assets (scripts, styles, etc),
+you'll need to run the application with the `dev` profile:
+
+```sh
+./gradlew bootRun --args='--spring.profiles.active=dev'
+```
+
+Otherwise, for the complete server (backend APIs + web interface), you can run:
 
 ```sh
 ./gradlew assemble && java -jar backend/build/libs/faidare.jar
@@ -71,18 +72,26 @@ Otherwise, for the complete server (backend APIs + frontend interface), you can
 
 The server should then be accessible at http://localhost:8380/faidare-dev
 
-## Run frontend development server
+## Build the JS/CSS assets for the Web module
 
-The frontend requests are redirected to the local backend API server (see instructions above to launch) via the
-Angular proxy.
+The `web` directory contains the scripts and styles used by the thymeleaf templates
+when a Germplasm, Study or Site page is rendered.
 
-You can run the development server with the following command:
+The build process for these assets can be run with the following command:
 
 ```sh
-cd frontend
-ng serve
+cd web
+yarn watch
 ```
 
+`yarn watch` automatically picks up the changes in any files,
+and rebuild the resulting assets (thanks to Webpack).
+Make sure the backend is running with the `dev` profile if you do so (see above),
+otherwise the changes won't be shown in the browser.
+
+`yarn watch:prod` is also available to use production settings,
+while `yarn build` and `yarn build:prod` do the same but without watching the changes. 
+
 ## Harvest
 
 Before all, take care to get data locally before running any indexing script.
@@ -94,8 +103,15 @@ Data indexing to your local Elasticsearch is done using the following command (t
 ```sh
 docker run -t --volume /path/to/local/data:/opt/data/ --network=container:elasticsearch-faidare registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:latest -jsonDir /opt/data/ --help
 ```
+
 Remove the `--help` parameter to run the loading with default params.
 
+If you depend on committed changes in indexing scripts under a specific branch (the docker image should have been automatically created by the CI), you need to change the tag of the docker image according to the branch name (ie. for branch `epic/merge-faidare-dd`, use tag `epic-merge-faidare-dd`, see `CI_COMMIT_REF_SLUG` [Gitlab predefined variable](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html#predefined-variables-reference)), as following:
+
+```sh
+docker run -t --volume /path/to/local/data:/opt/data/ --network=container:elasticsearch-faidare registry.forgemia.inra.fr/urgi-is/docker-rare/faidare-loader:epic-merge-faidare-dd` -jsonDir /opt/data/ --help
+```
+
 ### Portability
 
 #### Docker
diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts
index 9ff140544f08a54151ddf9ca56e164de76e37a35..0b2e2bcf637da7d52a26e8abcde00e4160a7769a 100644
--- a/backend/build.gradle.kts
+++ b/backend/build.gradle.kts
@@ -1,11 +1,8 @@
 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
 import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo
-import org.springframework.boot.gradle.tasks.bundling.BootJar
-import org.springframework.boot.gradle.tasks.run.BootRun
 
 buildscript {
     repositories {
-        mavenLocal()
         mavenCentral()
     }
 }
@@ -13,14 +10,13 @@ buildscript {
 plugins {
     java
     jacoco
-    id("org.springframework.boot") version "2.1.2.RELEASE"
-    id("com.gorylenko.gradle-git-properties") version "1.5.2"
-    id("io.spring.dependency-management") version "1.0.6.RELEASE"
+    id("org.springframework.boot") version "2.6.10"
+    id("com.gorylenko.gradle-git-properties") version "2.4.0"
+    id("io.spring.dependency-management") version "1.0.11.RELEASE"
     id("org.sonarqube")
-    id("org.owasp.dependencycheck") version "6.0.3"
+    id("org.owasp.dependencycheck") version "7.0.0"
 }
 
-
 java {
     sourceCompatibility = JavaVersion.VERSION_1_8
 }
@@ -29,8 +25,6 @@ repositories {
     mavenCentral()
 }
 
-val snippetsDir = file("build/generated-snippets")
-
 tasks {
 
     withType(JavaCompile::class.java) {
@@ -40,85 +34,102 @@ tasks {
         options.compilerArgs.add("-parameters")
     }
 
-    getByName<Copy>("processResources") {
-        inputs.property("app", "gnpis")
-
-        filesMatching("bootstrap.yml") {}
-    }
-
     // this task is always out-of-date because it generates a properties file with the build time inside
     // so the bootJar task is also always out of date, too, since it depends on it
     // but it's better to do that than using the bootInfo() method of the springBoot closure, because that
     // makes the test task out of date, which makes the build much longer.
     // See https://github.com/spring-projects/spring-boot/issues/13152
-    val buildInfo by creating(BuildInfo::class) {
+    val buildInfo by registering(BuildInfo::class) {
         destinationDir = file("$buildDir/buildInfo")
     }
 
-    val bootJar by getting(BootJar::class) {
-        archiveName = "${rootProject.name}.jar"
-        dependsOn(":frontend:assemble")
+    bootJar {
+        archiveFileName.set("${rootProject.name}.jar")
         dependsOn(buildInfo)
-
-        into("BOOT-INF/classes/static") {
-            from("${project(":frontend").projectDir}/dist/frontend")
+        dependsOn(":web:assemble")
+
+        // replace the script.js and style.css file names referenced in main.html
+        // by their actual name, containing the content hash
+        filesMatching("**/layout/main.html") {
+            val webAssetsDir = project(":web").file("build/dist/resources/");
+            val scriptFileName = webAssetsDir.list().first { it.startsWith("script") && it.endsWith(".js") }
+            val styleFileName = webAssetsDir.list().first { it.startsWith("style") && it.endsWith(".css") }
+
+            filter { line ->
+                if (line.contains("script.js")) {
+                    line.replace("script.js", scriptFileName)
+                }
+                else if (line.contains("style.css")) {
+                    line.replace("style.css", styleFileName)
+                } else {
+                    line
+                }
+            }
         }
+
         into("BOOT-INF/classes/META-INF") {
-            from(buildInfo.destinationDir)
+            from(buildInfo.map { it.destinationDir })
+        }
+        into("BOOT-INF/classes/static") {
+            from(project(":web").file("build/dist"))
         }
         launchScript()
     }
 
-    val test by getting(Test::class) {
+    test {
         useJUnitPlatform()
         testLogging {
             exceptionFormat = TestExceptionFormat.FULL
         }
-        outputs.dir(snippetsDir)
     }
 
-    val jacocoTestReport by getting(JacocoReport::class) {
+    jacocoTestReport {
         reports {
-            xml.setEnabled(true)
-            html.setEnabled(true)
+            xml.required.set(true)
+            html.required.set(true)
         }
     }
 }
 
+extra["springCloudVersion"] = "2021.0.1"
 dependencyManagement {
     imports {
-        mavenBom("org.springframework.cloud:spring-cloud-dependencies:Finchley.SR1")
+        mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
     }
 }
 
 dependencies {
+    constraints {
+        implementation("org.apache.logging.log4j:log4j-core") {
+            version {
+                strictly("[2.17, 3[")
+                prefer("2.17.0")
+            }
+            because("CVE-2021-44228, CVE-2021-45046, CVE-2021-45105: Log4j vulnerable to remote code execution and other critical security vulnerabilities")
+        }
+    }
     // Spring
     annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
+
     implementation("org.springframework.boot:spring-boot-starter-web")
+    implementation("org.springframework.boot:spring-boot-starter-validation")
     implementation("org.springframework.boot:spring-boot-starter-actuator")
     implementation("org.springframework.boot:spring-boot-starter-security")
     implementation("org.springframework.cloud:spring-cloud-starter-config")
+    implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
 
     // Elasticsearch
-    implementation("org.elasticsearch:elasticsearch:6.6.2")
-    implementation("org.elasticsearch.client:elasticsearch-rest-high-level-client:6.6.2")
+    implementation("org.elasticsearch:elasticsearch")
+    implementation("org.elasticsearch.client:elasticsearch-rest-high-level-client")
 
     // Swagger
-    implementation("io.swagger:swagger-annotations:1.5.21")
-    implementation("io.springfox:springfox-swagger2:2.9.2")
-    implementation("io.springfox:springfox-swagger-ui:2.9.2")
+    implementation("org.springdoc:springdoc-openapi-ui:1.6.6")
 
     // Others
-    implementation("com.google.guava:guava:27.0.1-jre")
-    implementation("com.opencsv:opencsv:4.4")
+    implementation("com.google.guava:guava:31.1-jre")
+    implementation("com.opencsv:opencsv:5.6")
 
     // Test dependencies
-    testImplementation("org.springframework.boot:spring-boot-starter-test") {
-        exclude(module = "junit")
-    }
-    testImplementation("org.junit.jupiter:junit-jupiter-api")
-    testImplementation("org.junit.jupiter:junit-jupiter-params")
-    testImplementation("org.mockito:mockito-junit-jupiter:2.23.0")
-    testImplementation("org.junit-pioneer:junit-pioneer:0.3.0")
-    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
+    testImplementation("org.springframework.boot:spring-boot-starter-test")
+    testImplementation("org.jsoup:jsoup:1.14.3")
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/CallsController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/CallsController.java
index b2bc193af41580435493cc50f6d36cd4fe0be74d..3ab6049edda81056a456a667cbd5f99039f82ff9 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/CallsController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/CallsController.java
@@ -1,31 +1,34 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ImmutableSet;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiCall;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiListResponse;
 import fr.inra.urgi.faidare.domain.criteria.base.PaginationCriteriaImpl;
 import fr.inra.urgi.faidare.domain.data.CallVO;
 import fr.inra.urgi.faidare.domain.response.ApiResponseFactory;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springdoc.webmvc.api.OpenApiWebMvcResource;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
-import springfox.documentation.service.ApiDescription;
-import springfox.documentation.service.Documentation;
-import springfox.documentation.spring.web.DocumentationCache;
-import springfox.documentation.spring.web.plugins.Docket;
-
-import javax.validation.Valid;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * @author gcornut
  */
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class CallsController {
     private static final String BRAPI_PATH = "/brapi/v1/";
@@ -39,28 +42,28 @@ public class CallsController {
         "1.1",
         "1.2"
     );
+    private final OpenApiWebMvcResource openApiResource;
+    private final ObjectMapper objectMapper;
 
-    private List<BrapiCall> implementedCalls;
+    private AtomicReference<List<BrapiCall>> implementedCalls = new AtomicReference<>(null);
 
-    private final DocumentationCache documentationCache;
-
-    @Autowired
-    public CallsController(DocumentationCache documentationCache) {
-        this.documentationCache = documentationCache;
+    public CallsController(OpenApiWebMvcResource openApiResource, ObjectMapper objectMapper) {
+        this.openApiResource = openApiResource;
+        this.objectMapper = objectMapper;
     }
 
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Calls/Calls.md
      */
-    @ApiOperation("List implemented Breeding API calls")
+    @Operation(summary = "List implemented Breeding API calls")
     @GetMapping("/brapi/v1/calls")
-    public BrapiListResponse<BrapiCall> calls(@Valid PaginationCriteriaImpl criteria) {
-        if (implementedCalls == null) {
-            implementedCalls = swaggerToBrapiCalls();
+    public BrapiListResponse<BrapiCall> calls(@Valid PaginationCriteriaImpl criteria, HttpServletRequest request) throws JsonProcessingException {
+        if (implementedCalls.get() == null) {
+            implementedCalls.set(swaggerToBrapiCalls(request));
         }
 
         return ApiResponseFactory.createSubListResponse(
-            criteria.getPageSize(), criteria.getPage(), implementedCalls
+            criteria.getPageSize(), criteria.getPage(), implementedCalls.get()
         );
     }
 
@@ -70,39 +73,25 @@ public class CallsController {
      * This must be done after swagger has time to generate the API
      * documentation and thus can't be done in this class constructor
      */
-    private List<BrapiCall> swaggerToBrapiCalls() {
-        Documentation apiDocumentation = this.documentationCache.documentationByGroup(Docket.DEFAULT_GROUP_NAME);
-
-        // Get all endpoints
-        return apiDocumentation.getApiListings().values().stream()
-            .flatMap(endpointListing -> endpointListing.getApis().stream())
-            // Only with BrAPI path
-            .filter(endpointDescription -> endpointDescription.getPath().startsWith(BRAPI_PATH))
-            // Group by endpoint path (ex: /brapi/v1/phenotype => [GET, POST, ...])
-            .collect(Collectors.groupingBy(ApiDescription::getPath))
-            .entrySet().stream()
-            // Convert to BrAPI call
-            .map(endpointGroup -> {
-                String path = endpointGroup.getKey();
-                List<ApiDescription> endpoints = endpointGroup.getValue();
-
-                // BrAPI call path should not include the base BrAPI path
+    @SuppressWarnings("unchecked")
+    private List<BrapiCall> swaggerToBrapiCalls(HttpServletRequest request) throws JsonProcessingException {
+        String json = openApiResource.openapiJson(request, "/v3/api-docs", Locale.ENGLISH);
+
+        Map<String, Object> map = objectMapper.readValue(json,
+                                                         new TypeReference<Map<String, Object>>() {});
+
+        Map<String, Object> pathMap = (Map<String, Object>) map.get("paths");
+        return pathMap.entrySet().stream()
+            .filter(entry -> entry.getKey().startsWith(BRAPI_PATH))
+            .map(entry -> {
+                String path = entry.getKey();
+                Map<String, Object> methodMap = (Map<String, Object>) entry.getValue();
+                Set<String> methods = methodMap.keySet().stream().map(String::toUpperCase).collect(Collectors.toSet());
                 CallVO call = new CallVO(path.replace(BRAPI_PATH, ""));
-
-                // List every endpoint for current path
-                Set<String> methods = endpoints.stream()
-                    // List all operations for each endpoint
-                    .flatMap(endpointDescription -> endpointDescription.getOperations().stream())
-                    // List all methods
-                    .map(operation -> operation.getMethod().toString())
-                    .collect(Collectors.toSet());
                 call.setMethods(methods);
-
                 return call;
             })
-            // Sort by call name
             .sorted(Comparator.comparing(CallVO::getCall))
             .collect(Collectors.toList());
     }
-
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmController.java
index 2ea27ac7c0c900626eb9d72ec8bf6054d5ac112e..922258cce393b3ed7a118c8bd4370585fb07e68e 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmController.java
@@ -1,5 +1,10 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+import java.util.List;
+import javax.validation.Valid;
+
 import fr.inra.urgi.faidare.api.NotFoundException;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiGermplasm;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiGermplasmAttributeValueList;
@@ -18,19 +23,19 @@ import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.domain.response.Pagination;
 import fr.inra.urgi.faidare.repository.es.GermplasmAttributeRepository;
 import fr.inra.urgi.faidare.service.es.GermplasmService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-import javax.validation.Valid;
-import java.util.List;
-
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
-
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class GermplasmController {
 
@@ -48,7 +53,7 @@ public class GermplasmController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Germplasm/GermplasmDetailsByGermplasmDbId.md
      */
-    @ApiOperation("Get germplasm by id")
+    @Operation(summary = "Get germplasm by id")
     @GetMapping("/brapi/v1/germplasm/{germplasmDbId}")
     public BrapiResponse<BrapiGermplasm> getGermplasm(@PathVariable String germplasmDbId) {
         LOGGER.debug("germplasmDbId = " + germplasmDbId);
@@ -59,7 +64,7 @@ public class GermplasmController {
         return ApiResponseFactory.createSingleObjectResponse(germplasm, null);
     }
 
-    @ApiOperation("List germplasm")
+    @Operation(summary = "List germplasm")
     @GetMapping("/brapi/v1/germplasm")
     public BrapiListResponse<? extends BrapiGermplasm> listGermplasm(
         @Valid PaginationCriteriaImpl paginationCriteria
@@ -73,7 +78,7 @@ public class GermplasmController {
     /**
      * @link https://brapi.docs.apiary.io/#reference/germplasm/germplasm/get-germplasm-mcpd-by-germplasmdbid
      */
-    @ApiOperation("Get germplasm mcpd by id")
+    @Operation(summary = "Get germplasm mcpd by id")
     @GetMapping("/brapi/v1/germplasm/{germplasmDbId}/mcpd")
     public BrapiResponse<GermplasmMcpdVO> getGermplasmMcpd(@PathVariable String germplasmDbId) {
         LOGGER.debug("germplasmDbId = " + germplasmDbId);
@@ -88,7 +93,7 @@ public class GermplasmController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Germplasm/GermplasmSearchGET.md
      */
-    @ApiOperation("Search germplasm")
+    @Operation(summary = "Search germplasm")
     @GetMapping(value = "/brapi/v1/germplasm-search")
     public BrapiListResponse<? extends BrapiGermplasm> searchGermplasm(
         @Valid GermplasmGETSearchCriteria criteria
@@ -99,7 +104,7 @@ public class GermplasmController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Germplasm/GermplasmSearchPOST.md
      */
-    @ApiOperation("Search germplasm")
+    @Operation(summary = "Search germplasm")
     @PostMapping(value = "/brapi/v1/germplasm-search", consumes = APPLICATION_JSON_VALUE)
     public BrapiListResponse<? extends BrapiGermplasm> searchGermplasm(
         @Valid @RequestBody(required = false) GermplasmPOSTSearchCriteria criteria
@@ -116,7 +121,7 @@ public class GermplasmController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/GermplasmAttributes/GermplasmAttributeValuesByGermplasmDbId.md
      */
-    @ApiOperation("List germplasm attributes")
+    @Operation(summary = "List germplasm attributes")
     @GetMapping("/brapi/v1/germplasm/{germplasmDbId}/attributes")
     public BrapiResponse<BrapiGermplasmAttributeValueList> listGermplasmAttributes(
         @PathVariable String germplasmDbId,
@@ -139,7 +144,7 @@ public class GermplasmController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/GermplasmAttributes/GermplasmAttributeValuesByGermplasmDbId.md
      */
-    @ApiOperation("Get germplasm pedigree")
+    @Operation(summary = "Get germplasm pedigree")
     @GetMapping("/brapi/v1/germplasm/{germplasmDbId}/pedigree")
     public BrapiResponse<BrapiPedigree> getPedigree(
         @PathVariable String germplasmDbId
@@ -151,7 +156,7 @@ public class GermplasmController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Germplasm/Germplasm_GermplasmDbId_Progeny_GET.yaml
      */
-    @ApiOperation("Get germplasm progeny")
+    @Operation(summary = "Get germplasm progeny")
     @GetMapping("/brapi/v1/germplasm/{germplasmDbId}/progeny")
     public BrapiResponse<BrapiProgeny> getProgeny(
         @PathVariable String germplasmDbId
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/LocationController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/LocationController.java
index 2cfec94ad00c7dac6a23f8f22bd161739b56a856..87850e3d7447e5d6b4003f87caf6b9ac0c6ec9f6 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/LocationController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/LocationController.java
@@ -1,5 +1,7 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import javax.validation.Valid;
+
 import fr.inra.urgi.faidare.api.NotFoundException;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiLocation;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiListResponse;
@@ -8,19 +10,17 @@ import fr.inra.urgi.faidare.domain.criteria.LocationCriteria;
 import fr.inra.urgi.faidare.domain.response.ApiResponseFactory;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.repository.es.LocationRepository;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.Valid;
-
 /**
  * @author gcornut
  */
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class LocationController {
 
@@ -34,7 +34,7 @@ public class LocationController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Locations/LocationDetails.md
      */
-    @ApiOperation("Get location")
+    @Operation(summary = "Get location")
     @GetMapping("/brapi/v1/locations/{locationDbId}")
     public BrapiResponse<BrapiLocation> getLocation(@PathVariable String locationDbId) {
         BrapiLocation location = repository.getById(locationDbId);
@@ -47,7 +47,7 @@ public class LocationController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Locations/ListLocations.md
      */
-    @ApiOperation("List locations")
+    @Operation(summary = "List locations")
     @GetMapping("/brapi/v1/locations")
     public BrapiListResponse<? extends BrapiLocation> listLocations(
         @Valid LocationCriteria criteria
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableController.java
index e19b3f8e112e148b1ef33506590e6cd2f1cff221..b2fc03486e8b4c6d58f5cb90a99b130e267505c8 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableController.java
@@ -1,5 +1,8 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import java.util.List;
+import javax.validation.Valid;
+
 import fr.inra.urgi.faidare.api.NotFoundException;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiObservationVariable;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiOntology;
@@ -9,22 +12,19 @@ import fr.inra.urgi.faidare.domain.criteria.ObservationVariableCriteria;
 import fr.inra.urgi.faidare.domain.criteria.base.PaginationCriteriaImpl;
 import fr.inra.urgi.faidare.domain.response.ApiResponseFactory;
 import fr.inra.urgi.faidare.repository.file.CropOntologyRepository;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.Valid;
-import java.util.List;
-
 /**
  * @author gcornut
  */
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class ObservationVariableController {
 
@@ -38,7 +38,7 @@ public class ObservationVariableController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/ObservationVariables/VariableDetails.md
      */
-    @ApiOperation("Get variable")
+    @Operation(summary = "Get variable")
     @GetMapping("/brapi/v1/variables/{observationVariableDbId}")
     public BrapiResponse<BrapiObservationVariable> getVariable(@PathVariable String observationVariableDbId) {
         BrapiObservationVariable variable = repository.getVariableById(observationVariableDbId);
@@ -51,10 +51,10 @@ public class ObservationVariableController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/ObservationVariables/VariableOntologyList.md
      */
-    @ApiOperation("List ontologies")
+    @Operation(summary = "List ontologies")
     @GetMapping("/brapi/v1/ontologies")
     public BrapiListResponse<? extends BrapiOntology> listOntologies(
-        @Valid @ApiParam PaginationCriteriaImpl criteria
+        @Valid @Parameter PaginationCriteriaImpl criteria
     ) {
         List<? extends BrapiOntology> ontologies = repository.getOntologies();
 
@@ -67,10 +67,10 @@ public class ObservationVariableController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/ObservationVariables/VariableList.md
      */
-    @ApiOperation("List variables")
+    @Operation(summary = "List variables")
     @GetMapping("/brapi/v1/variables")
     public BrapiListResponse<? extends BrapiObservationVariable> listVariables(
-        @Valid @ApiParam ObservationVariableCriteria criteria
+        @Valid @Parameter ObservationVariableCriteria criteria
     ) {
         // Get variables by trait class or get all variables
         List<? extends BrapiObservationVariable> variables;
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/PhenotypeController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/PhenotypeController.java
index 3aab607c9ed04fa95d046462bcc75a52dee191f1..f74e27bbed832f007229a257237e2074b0896123 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/PhenotypeController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/PhenotypeController.java
@@ -1,26 +1,26 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+import javax.validation.Valid;
+
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiObservationUnit;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiListResponse;
 import fr.inra.urgi.faidare.domain.criteria.ObservationUnitCriteria;
 import fr.inra.urgi.faidare.domain.response.ApiResponseFactory;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.repository.es.ObservationUnitRepository;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.Valid;
-
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
-
 /**
  * @author gcornut
  */
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class PhenotypeController {
 
@@ -34,7 +34,7 @@ public class PhenotypeController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Phenotypes/PhenotypeSearch.md
      */
-    @ApiOperation("Search phenotypes")
+    @Operation(summary = "Search phenotypes")
     @PostMapping(value = "/brapi/v1/phenotypes-search", consumes = APPLICATION_JSON_VALUE)
     public BrapiListResponse<? extends BrapiObservationUnit> searchPhenotypes(@Valid @RequestBody(required = false) ObservationUnitCriteria criteria) {
         PaginatedList<? extends BrapiObservationUnit> result = repository.find(criteria);
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramController.java
index 8a892c8b057aad664d0c446adfab8cbbb550d4e9..89c1e49db7ade1e1fe3c05d1815b9d244e69ab4c 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramController.java
@@ -1,5 +1,9 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+import javax.validation.Valid;
+
 import fr.inra.urgi.faidare.api.NotFoundException;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiProgram;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiListResponse;
@@ -9,20 +13,20 @@ import fr.inra.urgi.faidare.domain.data.ProgramVO;
 import fr.inra.urgi.faidare.domain.response.ApiResponseFactory;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.repository.es.ProgramRepository;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-import javax.validation.Valid;
-
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
  * @author gcornut
  */
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class ProgramController {
 
@@ -36,7 +40,7 @@ public class ProgramController {
     /**
      * Not officially present in BrAPI
      */
-    @ApiOperation("Get program")
+    @Operation(summary = "Get program")
     @GetMapping("/brapi/v1/programs/{programDbId}")
     public BrapiResponse<BrapiProgram> getProgram(@PathVariable String programDbId) {
         ProgramVO program = repository.getById(programDbId);
@@ -49,9 +53,9 @@ public class ProgramController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Programs/ListPrograms.md
      */
-    @ApiOperation("List programs")
+    @Operation(summary = "List programs")
     @GetMapping("/brapi/v1/programs")
-    public BrapiListResponse<? extends BrapiProgram> listPrograms(@Valid @ApiParam ProgramCriteria criteria) {
+    public BrapiListResponse<? extends BrapiProgram> listPrograms(@Valid @Parameter ProgramCriteria criteria) {
         PaginatedList<ProgramVO> result = repository.find(criteria);
         return ApiResponseFactory.createListResponse(result.getPagination(), null, result);
     }
@@ -59,7 +63,7 @@ public class ProgramController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Programs/ProgramSearch.md
      */
-    @ApiOperation("Search programs")
+    @Operation(summary = "Search programs")
     @PostMapping(value = "/brapi/v1/programs-search", consumes = APPLICATION_JSON_VALUE)
     public BrapiListResponse<? extends BrapiProgram> searchPrograms(@Valid @RequestBody(required = false) ProgramCriteria criteria) {
         return listPrograms(criteria);
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/StudyController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/StudyController.java
index 39b2f72d759ff78a549af444893992a7a9f438f3..2411dcfebfaab53cb91b77c6192144ed36571313 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/StudyController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/StudyController.java
@@ -1,12 +1,26 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+import java.util.List;
+import java.util.Set;
+import javax.validation.Valid;
+
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import fr.inra.urgi.faidare.api.NotFoundException;
-import fr.inra.urgi.faidare.domain.brapi.v1.data.*;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiGermplasm;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiObservationUnit;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiObservationVariable;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiStudyDetail;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiStudySummary;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiListResponse;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiResponse;
-import fr.inra.urgi.faidare.domain.criteria.*;
+import fr.inra.urgi.faidare.domain.criteria.GermplasmPOSTSearchCriteria;
+import fr.inra.urgi.faidare.domain.criteria.ObservationUnitCriteria;
+import fr.inra.urgi.faidare.domain.criteria.StudyObservationUnitCriteria;
+import fr.inra.urgi.faidare.domain.criteria.StudySearchCriteria;
+import fr.inra.urgi.faidare.domain.criteria.StudySummaryCriteria;
 import fr.inra.urgi.faidare.domain.criteria.base.PaginationCriteriaImpl;
 import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
 import fr.inra.urgi.faidare.domain.data.phenotype.ObservationUnitVO;
@@ -21,22 +35,20 @@ import fr.inra.urgi.faidare.repository.es.ObservationUnitRepository;
 import fr.inra.urgi.faidare.repository.es.StudyRepository;
 import fr.inra.urgi.faidare.repository.file.CropOntologyRepository;
 import fr.inra.urgi.faidare.utils.StringFunctions;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-import javax.validation.Valid;
-import java.util.List;
-import java.util.Set;
-
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
  * @author gcornut
  */
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class StudyController {
 
@@ -61,7 +73,7 @@ public class StudyController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Studies/StudyDetails.md
      */
-    @ApiOperation("Get study")
+    @Operation(summary = "Get study")
     @GetMapping("/brapi/v1/studies/{studyDbId}")
     public BrapiResponse<BrapiStudyDetail> getStudy(@PathVariable String studyDbId) throws Exception {
         studyDbId = StringFunctions.asUTF8(studyDbId);
@@ -75,7 +87,7 @@ public class StudyController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Studies/ListStudySummaries.md
      */
-    @ApiOperation("List studies")
+    @Operation(summary = "List studies")
     @GetMapping("/brapi/v1/studies")
     public BrapiListResponse<? extends BrapiStudySummary> listStudies(@Valid StudySummaryCriteria criteria) {
         if (criteria == null) {
@@ -88,7 +100,7 @@ public class StudyController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Studies/SearchStudies.md
      */
-    @ApiOperation("Search studies")
+    @Operation(summary = "Search studies")
     @GetMapping(value = "/brapi/v1/studies-search")
     public BrapiListResponse<? extends BrapiStudySummary> searchStudiesGet(@Valid StudySearchCriteria criteria) {
         return listStudies(criteria);
@@ -97,7 +109,7 @@ public class StudyController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Studies/SearchStudies.md
      */
-    @ApiOperation("Search studies")
+    @Operation(summary = "Search studies")
     @PostMapping(value = "/brapi/v1/studies-search", consumes = APPLICATION_JSON_VALUE)
     public BrapiListResponse<? extends BrapiStudySummary> searchStudiesPost(@RequestBody(required = false) @Valid StudySearchCriteria criteria) {
         return listStudies(criteria);
@@ -106,7 +118,7 @@ public class StudyController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Studies/StudyObservationVariables.md
      */
-    @ApiOperation("List study observation variables")
+    @Operation(summary = "List study observation variables")
     @GetMapping(value = {"/brapi/v1/studies/{studyDbId}/observationVariables", "/brapi/v1/studies/{studyDbId}/observationvariables"})
     public BrapiListResponse<? extends BrapiObservationVariable> listStudyVariables(
         @PathVariable String studyDbId, @Valid PaginationCriteriaImpl criteria
@@ -128,7 +140,7 @@ public class StudyController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Studies/ObservationUnitDetails.md
      */
-    @ApiOperation("List study observation units")
+    @Operation(summary = "List study observation units")
     @GetMapping(value = {"/brapi/v1/studies/{studyDbId}/observationUnits", "/brapi/v1/studies/{studyDbId}/observationunits"})
     public BrapiListResponse<? extends BrapiObservationUnit> listStudyObservationUnits(
         @PathVariable String studyDbId, @Valid StudyObservationUnitCriteria criteria
@@ -146,7 +158,7 @@ public class StudyController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Studies/StudyGermplasmDetails.md
      */
-    @ApiOperation("List study germplasm")
+    @Operation(summary = "List study germplasm")
     @GetMapping("/brapi/v1/studies/{studyDbId}/germplasm")
     public BrapiListResponse<? extends BrapiGermplasm> listStudyGermplasm(
         @PathVariable String studyDbId, @Valid PaginationCriteriaImpl criteria
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/TrialController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/TrialController.java
index 7a49b76c5c3a5d69d2daccd2106e41cb7d36f6ae..f936d47e7fd492e9ee694e4699a7e44fb8e5a379 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/TrialController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/brapi/v1/TrialController.java
@@ -1,5 +1,7 @@
 package fr.inra.urgi.faidare.api.brapi.v1;
 
+import javax.validation.Valid;
+
 import fr.inra.urgi.faidare.api.NotFoundException;
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiTrial;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiListResponse;
@@ -9,19 +11,17 @@ import fr.inra.urgi.faidare.domain.data.TrialVO;
 import fr.inra.urgi.faidare.domain.response.ApiResponseFactory;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.repository.es.TrialRepository;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.validation.Valid;
-
 /**
  * @author gcornut
  */
-@Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
+@Tag(name = "Breeding API", description = "BrAPI endpoint")
 @RestController
 public class TrialController {
 
@@ -35,7 +35,7 @@ public class TrialController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Trials/GetTrialById.md
      */
-    @ApiOperation("Get trial")
+    @Operation(summary = "Get trial")
     @GetMapping("/brapi/v1/trials/{trialDbId}")
     public BrapiResponse<BrapiTrial> getTrial(@PathVariable String trialDbId) {
         TrialVO program = repository.getById(trialDbId);
@@ -48,7 +48,7 @@ public class TrialController {
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Trials/ListTrialSummaries.md
      */
-    @ApiOperation("List trials")
+    @Operation(summary = "List trials")
     @GetMapping("/brapi/v1/trials")
     public BrapiListResponse<? extends BrapiTrial> listTrials(@Valid TrialCriteria criteria) {
         PaginatedList<? extends BrapiTrial> result = repository.find(criteria);
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/DataDiscoveryController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/DataDiscoveryController.java
index b4bef53dadfe12a81db4da50aedfc7637d8f8e56..3956a70263a7b60b65fda9092f5eb794adfb599b 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/DataDiscoveryController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/DataDiscoveryController.java
@@ -1,5 +1,12 @@
 package fr.inra.urgi.faidare.api.faidare.v1;
 
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.List;
+import javax.validation.Valid;
+
 import fr.inra.urgi.faidare.config.FaidareProperties;
 import fr.inra.urgi.faidare.domain.brapi.v1.response.BrapiListResponse;
 import fr.inra.urgi.faidare.domain.datadiscovery.criteria.DataDiscoveryCriteriaImpl;
@@ -9,19 +16,17 @@ import fr.inra.urgi.faidare.domain.datadiscovery.response.DataDiscoveryResponse;
 import fr.inra.urgi.faidare.domain.response.ApiResponseFactory;
 import fr.inra.urgi.faidare.repository.es.DataDiscoveryRepository;
 import fr.inra.urgi.faidare.utils.StringFunctions;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-import javax.validation.Valid;
-import java.io.UnsupportedEncodingException;
-import java.util.Collection;
-import java.util.List;
-
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
-@Api(tags = {"FAIDARE API"}, description = "Extended FAIDARE API")
+@Tag(name = "FAIDARE API", description = "Extended FAIDARE API")
 @RestController
 @RequestMapping(value = "/faidare/v1/datadiscovery")
 public class DataDiscoveryController {
@@ -35,7 +40,7 @@ public class DataDiscoveryController {
         this.properties = properties;
     }
 
-    @ApiOperation("Suggest data discovery document field values")
+    @Operation(summary = "Suggest data discovery document field values")
     @PostMapping("/suggest")
     public Collection<String> suggest(
         @RequestParam String field,
@@ -49,7 +54,7 @@ public class DataDiscoveryController {
         return dataDiscoveryRepository.suggest(field, StringFunctions.asUTF8(text), fetchSize, criteria);
     }
 
-    @ApiOperation("Search for data discovery documents")
+    @Operation(summary = "Search for data discovery documents")
     @PostMapping(value = "/search", consumes = APPLICATION_JSON_VALUE)
     public DataDiscoveryResponse search(
         @RequestBody @Valid DataDiscoveryCriteriaImpl criteria
@@ -57,7 +62,7 @@ public class DataDiscoveryController {
         return dataDiscoveryRepository.find(criteria);
     }
 
-    @ApiOperation("Get list of data sources")
+    @Operation(summary = "Get list of data sources")
     @GetMapping("/sources")
     public BrapiListResponse<? extends DataSource> sources() {
         List<DataSourceImpl> dataSources = properties.getDataSources();
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmController.java
index 70c262b935def1c8f2bf8a6037e8c7d0fec34598..1c92aa098bde6237f3b468a07a1b19b0f32f7e89 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmController.java
@@ -1,5 +1,12 @@
 package fr.inra.urgi.faidare.api.faidare.v1;
 
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+import java.io.File;
+import java.util.Collections;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+
 import com.google.common.base.Strings;
 import fr.inra.urgi.faidare.api.BadRequestException;
 import fr.inra.urgi.faidare.api.NotFoundException;
@@ -11,22 +18,20 @@ import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
 import fr.inra.urgi.faidare.domain.datadiscovery.response.GermplasmSearchResponse;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.service.es.GermplasmService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.FileSystemResource;
-import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletResponse;
-import javax.validation.Valid;
-import java.io.File;
-import java.util.Collections;
-
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
-
-@Api(tags = {"FAIDARE API"}, description = "Extended FAIDARE API")
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@Tag(name = "FAIDARE API", description = "Extended FAIDARE API")
 @RestController
 @RequestMapping(value = "/faidare/v1/germplasm")
 public class GnpISGermplasmController {
@@ -39,7 +44,7 @@ public class GnpISGermplasmController {
         this.germplasmService = germplasmService;
     }
 
-    @ApiOperation(value = "Search germplasm by ID or PUI")
+    @Operation(summary = "Search germplasm by ID or PUI")
     @GetMapping
     public GermplasmVO get(
         @RequestParam(required = false) String id,
@@ -147,7 +152,7 @@ public class GnpISGermplasmController {
         return null;
     }
 
-    @ApiOperation("Search list of germplasm")
+    @Operation(summary = "Search list of germplasm")
     @PostMapping(value = "/search", consumes = APPLICATION_JSON_VALUE)
     public GermplasmSearchResponse germplasmSearch(@RequestBody @Valid FaidareGermplasmPOSTShearchCriteria criteria) {
         try {
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/XRefDocumentController.java b/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/XRefDocumentController.java
index 14b8f046089a6df7d267700a8c00f784c94081b0..af79dc6b08ff9b65485865590783088f1b5f5342 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/XRefDocumentController.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/api/faidare/v1/XRefDocumentController.java
@@ -1,23 +1,23 @@
 package fr.inra.urgi.faidare.api.faidare.v1;
 
+import java.util.List;
+
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.domain.xref.XRefDocumentSearchCriteria;
 import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
 import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.List;
-
 
 /**
  * Imported and adapted from unified-interface legacy
  */
-@Api(tags = {"FAIDARE API"}, description = "Extended FAIDARE API")
+@Tag(name = "FAIDARE API", description = "Extended FAIDARE API")
 @RestController
 public class XRefDocumentController {
 
@@ -28,15 +28,15 @@ public class XRefDocumentController {
         this.repository = repository;
     }
 
-    @ApiOperation("Find xref documents")
+    @Operation(summary = "Find xref documents")
     @GetMapping(value = "/faidare/v1/xref/documentbyfulltextid")
     public PaginatedList<XRefDocumentVO> documentByFullTextId(
-        @RequestParam(required = false, value = "entry_type") String entryType,
-        @RequestParam(required = false) List<String> linkedRessourcesID
+        @RequestParam(required = false, value = "entryType") String entryType,
+        @RequestParam(required = false) List<String> linkedResourcesID
     ) {
         XRefDocumentSearchCriteria criteria = new XRefDocumentSearchCriteria();
         criteria.setEntryType(entryType);
-        criteria.setLinkedRessourcesID(linkedRessourcesID);
+        criteria.setLinkedResourcesID(linkedResourcesID);
 	return repository.find(criteria);
     }
 
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/config/ElasticSearchConfig.java b/backend/src/main/java/fr/inra/urgi/faidare/config/ElasticSearchConfig.java
index 8d4901f956946b6e21a6b74d978d5b44e72557ca..eee4827dca3792b60e65899368bff6232a46304b 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/config/ElasticSearchConfig.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/config/ElasticSearchConfig.java
@@ -6,7 +6,7 @@ import org.elasticsearch.client.NodeSelector;
 import org.elasticsearch.client.RestClient;
 import org.elasticsearch.client.RestClientBuilder;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration;
+import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -20,7 +20,7 @@ public class ElasticSearchConfig {
     private Integer esPort;
 
     /**
-     * Provides builder for {@link RestClientAutoConfiguration}
+     * Provides builder for {@link ElasticsearchRestClientAutoConfiguration}
      */
     @Bean
     public RestClientBuilder restClientBuilder() {
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/config/FaidareProperties.java b/backend/src/main/java/fr/inra/urgi/faidare/config/FaidareProperties.java
index c4cba9858db96ceb01def7b3a5c26d7bcf759722..ea790cf2a731e625f6ccf9b0843b7afd9ba4132a 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/config/FaidareProperties.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/config/FaidareProperties.java
@@ -31,6 +31,13 @@ public class FaidareProperties {
     private String securityUserGroupWsUrl;
     private String securityUserGroupWsToken;
 
+    /**
+     * The URL used by the germplasm card to generate links to the faidare search application
+     * (i.e. the faidare flavor of data-discovery).
+     */
+    @NotBlank
+    private String searchUrl;
+
     private List<DataSourceImpl> dataSources = new ArrayList<>();
 
     public String getElasticsearchIndexingTemplate() {
@@ -118,6 +125,11 @@ public class FaidareProperties {
             .replace("{documentType}", documentType.toLowerCase());
     }
 
+    public String getSearchUrl() {
+        return searchUrl;
+    }
 
-
+    public void setSearchUrl(String searchUrl) {
+        this.searchUrl = searchUrl;
+    }
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/config/SwaggerConfig.java b/backend/src/main/java/fr/inra/urgi/faidare/config/SwaggerConfig.java
index cfa2aad25a3a99b09833ab0b860a71287d265d3d..97173a1b3b4abb768df6548cffccf952b887e2de 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/config/SwaggerConfig.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/config/SwaggerConfig.java
@@ -1,26 +1,18 @@
 package fr.inra.urgi.faidare.config;
 
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 /**
  * @author gcornut
  */
 @Configuration
-@EnableSwagger2
 public class SwaggerConfig {
 
     @Bean
-    public Docket api() {
-        return new Docket(DocumentationType.SWAGGER_2).select()
-            .apis(RequestHandlerSelectors.basePackage("fr.inra.urgi.faidare.api"))
-            .paths(PathSelectors.regex("/.*"))
-            .build();
+    public OpenAPI springShopOpenAPI() {
+        return new OpenAPI().info(new Info().title("FAIDARE and BrAPI APIs"));
     }
-
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/brapi/v1/data/BrapiContact.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/brapi/v1/data/BrapiContact.java
index ef4d398c024c085bfc844107cde29432d83be7d4..ee711a321b15cabb7abf9118d0bf94c1f5867a8f 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/domain/brapi/v1/data/BrapiContact.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/brapi/v1/data/BrapiContact.java
@@ -25,7 +25,7 @@ public interface BrapiContact extends Serializable {
     String getType();
 
     @JsonView(JSONView.BrapiFields.class)
-    String getInstitutionName();
+    String getInstituteName();
 
     @JsonView(JSONView.BrapiFields.class)
     String getOrcid();
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/data/ContactVO.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/ContactVO.java
index 14a1c1ea4aa2920f8574fd5b69bca5074efd3955..dc381f5c433910f0f37673a6d108ab9dcd6514e3 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/domain/data/ContactVO.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/ContactVO.java
@@ -12,7 +12,7 @@ public class ContactVO implements BrapiContact {
     private String name;
     private String email;
     private String type;
-    private String institutionName;
+    private String instituteName;
     private String orcid;
 
     @Override
@@ -36,8 +36,8 @@ public class ContactVO implements BrapiContact {
     }
 
     @Override
-    public String getInstitutionName() {
-        return institutionName;
+    public String getInstituteName() {
+        return instituteName;
     }
 
     @Override
@@ -61,8 +61,8 @@ public class ContactVO implements BrapiContact {
         this.type = type;
     }
 
-    public void setInstitutionName(String institutionName) {
-        this.institutionName = institutionName;
+    public void setInstituteName(String instituteName) {
+        this.instituteName = instituteName;
     }
 
     public void setOrcid(String orcid) {
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/data/LocationSitemapVO.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/LocationSitemapVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ee34df29e0c81442293391c34f8947f08b5311e
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/LocationSitemapVO.java
@@ -0,0 +1,36 @@
+package fr.inra.urgi.faidare.domain.data;
+
+import java.util.List;
+
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiAdditionalInfo;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiLocation;
+import fr.inra.urgi.faidare.domain.jsonld.data.HasURI;
+import fr.inra.urgi.faidare.domain.jsonld.data.HasURL;
+import fr.inra.urgi.faidare.domain.jsonld.data.IncludedInDataCatalog;
+import fr.inra.urgi.faidare.elasticsearch.document.annotation.Document;
+import fr.inra.urgi.faidare.elasticsearch.document.annotation.Id;
+
+/**
+ * A minimal view of a location containing only its ID, used to generate sitemaps
+ */
+@Document(type = "location", includedFields = "locationDbId")
+public class LocationSitemapVO {
+
+    @Id
+    private String locationDbId;
+
+    public LocationSitemapVO() {
+    }
+
+    public LocationSitemapVO(String locationDbId) {
+        this.locationDbId = locationDbId;
+    }
+
+    public String getLocationDbId() {
+        return locationDbId;
+    }
+
+    public void setLocationDbId(String locationDbId) {
+        this.locationDbId = locationDbId;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/data/germplasm/GermplasmSitemapVO.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/germplasm/GermplasmSitemapVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7dc268148ed53309a64f4fbf808d5bdec580e68
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/germplasm/GermplasmSitemapVO.java
@@ -0,0 +1,38 @@
+package fr.inra.urgi.faidare.domain.data.germplasm;
+
+import java.io.Serializable;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonSetter;
+import com.fasterxml.jackson.annotation.Nulls;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiGermplasm;
+import fr.inra.urgi.faidare.domain.jsonld.data.HasURI;
+import fr.inra.urgi.faidare.domain.jsonld.data.HasURL;
+import fr.inra.urgi.faidare.domain.jsonld.data.IncludedInDataCatalog;
+import fr.inra.urgi.faidare.elasticsearch.document.annotation.Document;
+import fr.inra.urgi.faidare.elasticsearch.document.annotation.Id;
+
+/**
+ * A minimal view of a germplasm, containing only its ID, used for sitemaps
+ */
+@Document(type = "germplasm", includedFields = "germplasmDbId")
+public class GermplasmSitemapVO {
+
+    @Id
+    private String germplasmDbId;
+
+    public GermplasmSitemapVO() {
+    }
+
+    public GermplasmSitemapVO(String germplasmDbId) {
+        this.germplasmDbId = germplasmDbId;
+    }
+
+    public String getGermplasmDbId() {
+        return germplasmDbId;
+    }
+
+    public void setGermplasmDbId(String germplasmDbId) {
+        this.germplasmDbId = germplasmDbId;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/data/study/StudySitemapVO.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/study/StudySitemapVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4900361a93329fa4c623b71b4cebf7a360e49d6
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/data/study/StudySitemapVO.java
@@ -0,0 +1,40 @@
+package fr.inra.urgi.faidare.domain.data.study;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiAdditionalInfo;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiStudySummary;
+import fr.inra.urgi.faidare.domain.data.GnpISInternal;
+import fr.inra.urgi.faidare.domain.jsonld.data.HasURI;
+import fr.inra.urgi.faidare.domain.jsonld.data.HasURL;
+import fr.inra.urgi.faidare.domain.jsonld.data.IncludedInDataCatalog;
+import fr.inra.urgi.faidare.elasticsearch.document.annotation.Document;
+import fr.inra.urgi.faidare.elasticsearch.document.annotation.Id;
+
+/**
+ * A minimal view of a study containing only its ID, used to generate sitemaps
+ */
+@Document(type = "study", includedFields = "studyDbId")
+public class StudySitemapVO {
+
+    @Id
+    private String studyDbId;
+
+    public StudySitemapVO() {
+    }
+
+    public StudySitemapVO(String studyDbId) {
+        this.studyDbId = studyDbId;
+    }
+
+    public String getStudyDbId() {
+        return studyDbId;
+    }
+
+    public void setStudyDbId(String studyDbId) {
+        this.studyDbId = studyDbId;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/DocumentFields.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/DocumentFields.java
index af7420a01082796fdd1d467fdec2cca8d3efdccf..5a43e4d68a5522e54a328ae8fae803297da68eef 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/DocumentFields.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/DocumentFields.java
@@ -5,7 +5,7 @@ package fr.inra.urgi.faidare.domain.xref;
  */
 public enum DocumentFields {
 
-	ENTRY_TYPE("entry_type"), LINKEDRESSOURCESID("linkedRessourcesID");
+	ENTRY_TYPE("entryType"), LINKED_RESOURCES_ID("linkedResourcesID");
 
 	private String field;
 
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentSearchCriteria.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentSearchCriteria.java
index 7ca7b26afe0f212fa6c997315c92214409f74b88..e205689d39491b94e1ede89ef8d5a86397587c5d 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentSearchCriteria.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentSearchCriteria.java
@@ -4,6 +4,7 @@ import fr.inra.urgi.faidare.domain.criteria.base.PaginationCriteriaImpl;
 import fr.inra.urgi.faidare.elasticsearch.criteria.annotation.CriteriaForDocument;
 import fr.inra.urgi.faidare.elasticsearch.criteria.annotation.DocumentPath;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -12,11 +13,17 @@ import java.util.List;
 @CriteriaForDocument(XRefDocumentVO.class)
 public class XRefDocumentSearchCriteria extends PaginationCriteriaImpl {
 
-    @DocumentPath("entry_type")
+    @DocumentPath("entryType")
 	private String entryType;
 
-    @DocumentPath("linkedRessourcesID")
-	private List<String> linkedRessourcesID;
+    @DocumentPath("linkedResourcesID") // pragma: allowlist secret
+	private List<String> linkedResourcesID;
+
+    public static XRefDocumentSearchCriteria forXRefId(String resourceId) {
+        XRefDocumentSearchCriteria criteria = new XRefDocumentSearchCriteria();
+        criteria.setLinkedResourcesID(Collections.singletonList(resourceId));
+        return criteria;
+    }
 
     public String getEntryType() {
         return entryType;
@@ -26,11 +33,11 @@ public class XRefDocumentSearchCriteria extends PaginationCriteriaImpl {
         this.entryType = entryType;
     }
 
-    public List<String> getLinkedRessourcesID() {
-        return linkedRessourcesID;
+    public List<String> getLinkedResourcesID() {
+        return linkedResourcesID;
     }
 
-    public void setLinkedRessourcesID(List<String> linkedRessourcesID) {
-        this.linkedRessourcesID = linkedRessourcesID;
+    public void setLinkedResourcesID(List<String> linkedResourcesID) {
+        this.linkedResourcesID = linkedResourcesID;
     }
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentVO.java b/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentVO.java
index b6ae340faf0b51cffd5914df39958e687bd09ca5..9279936feda6dfa58266654667f15190c28dfafc 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentVO.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/domain/xref/XRefDocumentVO.java
@@ -11,23 +11,20 @@ import java.util.List;
  *
  * @author fphilippe
  */
-@Document(type = "transplant")
+@Document(type = "xref")
 public class XRefDocumentVO {
 
-    @JsonProperty("group_id")
+    @JsonProperty("groupId")
     private String groupId;
 
-    @JsonProperty("entry_type")
+    @JsonProperty("entryType")
     private String entryType;
 
-    @JsonProperty("database_name")
+    @JsonProperty("databaseName")
     private String databaseName;
 
-    @JsonProperty("db_id")
-    private String dbId;
-
-    @JsonProperty("db_version")
-    private String dbVersion;
+    @JsonProperty("identifier")
+    private String identifier;
 
     @JsonProperty("name")
     private String name;
@@ -39,60 +36,10 @@ public class XRefDocumentVO {
     private String url;
 
     @JsonProperty("species")
-    private String species;
-
-    @JsonProperty("xref")
-    private String xref;
-
-    @JsonProperty("feature_type")
-    private String featureType;
-
-    @JsonProperty("sequence_id")
-    private String sequenceId;
-
-    @JsonProperty("sequence_version")
-    private String sequence_version;
-
-    @JsonProperty("start_position")
-    private String startPosition;
-
-    @JsonProperty("end_position")
-    private String endPosition;
-
-    @JsonProperty("map")
-    private String map;
-
-    @JsonProperty("map_position")
-    private String mapPosition;
-
-    @JsonProperty("authority")
-    private String authority;
-
-    @JsonProperty("trait")
-    private String trait;
-
-    @JsonProperty("trait_id")
-    private String traitId;
+    private List<String> species;
 
-    @JsonProperty("environment")
-    private String environment;
-
-    @JsonProperty("environment_id")
-    private String environmentId;
-
-    @JsonProperty("statistic")
-    private String statistic;
-
-    @JsonProperty("unit")
-    private String unit;
-
-    @JsonProperty("genotype")
-    private String genotype;
-
-    @JsonProperty("experiment_type")
-    private String experimentType;
-
-    private List<String> linkedRessourcesID;
+    //@JsonProperty("linkedResourcesID")
+    private List<String> linkedResourcesID;
 
     public String getGroupId() {
         return groupId;
@@ -118,20 +65,12 @@ public class XRefDocumentVO {
         this.databaseName = databaseName;
     }
 
-    public String getDbId() {
-        return dbId;
+    public String getIdentifier() {
+        return identifier;
     }
 
-    public void setDbId(String dbId) {
-        this.dbId = dbId;
-    }
-
-    public String getDbVersion() {
-        return dbVersion;
-    }
-
-    public void setDbVersion(String dbVersion) {
-        this.dbVersion = dbVersion;
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
     }
 
     public String getName() {
@@ -158,156 +97,20 @@ public class XRefDocumentVO {
         this.url = url;
     }
 
-    public String getSpecies() {
+    public List<String> getSpecies() {
         return species;
     }
 
-    public void setSpecies(String species) {
+    public void setSpecies(List<String> species) {
         this.species = species;
     }
 
-    public String getXref() {
-        return xref;
-    }
-
-    public void setXref(String xref) {
-        this.xref = xref;
-    }
-
-    public String getFeatureType() {
-        return featureType;
-    }
-
-    public void setFeatureType(String featureType) {
-        this.featureType = featureType;
-    }
-
-    public String getSequenceId() {
-        return sequenceId;
-    }
-
-    public void setSequenceId(String sequenceId) {
-        this.sequenceId = sequenceId;
-    }
-
-    public String getSequence_version() {
-        return sequence_version;
-    }
-
-    public void setSequence_version(String sequence_version) {
-        this.sequence_version = sequence_version;
-    }
-
-    public String getStartPosition() {
-        return startPosition;
-    }
-
-    public void setStartPosition(String startPosition) {
-        this.startPosition = startPosition;
-    }
-
-    public String getEndPosition() {
-        return endPosition;
-    }
-
-    public void setEndPosition(String endPosition) {
-        this.endPosition = endPosition;
-    }
-
-    public String getMap() {
-        return map;
-    }
-
-    public void setMap(String map) {
-        this.map = map;
-    }
-
-    public String getMapPosition() {
-        return mapPosition;
-    }
-
-    public void setMapPosition(String mapPosition) {
-        this.mapPosition = mapPosition;
-    }
-
-    public String getAuthority() {
-        return authority;
-    }
-
-    public void setAuthority(String authority) {
-        this.authority = authority;
-    }
-
-    public String getTrait() {
-        return trait;
-    }
-
-    public void setTrait(String trait) {
-        this.trait = trait;
-    }
-
-    public String getTraitId() {
-        return traitId;
-    }
-
-    public void setTraitId(String traitId) {
-        this.traitId = traitId;
-    }
-
-    public String getEnvironment() {
-        return environment;
-    }
-
-    public void setEnvironment(String environment) {
-        this.environment = environment;
-    }
-
-    public String getEnvironmentId() {
-        return environmentId;
-    }
-
-    public void setEnvironmentId(String environmentId) {
-        this.environmentId = environmentId;
-    }
-
-    public String getStatistic() {
-        return statistic;
-    }
-
-    public void setStatistic(String statistic) {
-        this.statistic = statistic;
-    }
-
-    public String getUnit() {
-        return unit;
-    }
-
-    public void setUnit(String unit) {
-        this.unit = unit;
-    }
-
-    public String getGenotype() {
-        return genotype;
-    }
-
-    public void setGenotype(String genotype) {
-        this.genotype = genotype;
-    }
-
-    public String getExperimentType() {
-        return experimentType;
-    }
-
-    public void setExperimentType(String experimentType) {
-        this.experimentType = experimentType;
-    }
-
-    public List<String> getLinkedRessourcesID() {
-        return linkedRessourcesID;
+    public List<String> getLinkedResourcesID() {
+        return linkedResourcesID;
     }
 
-    public void setLinkedRessourcesID(List<String> linkedRessourcesID) {
-        this.linkedRessourcesID = linkedRessourcesID;
+    public void setLinkedResourcesID(List<String> linkedResourcesID) {
+        this.linkedResourcesID = linkedResourcesID;
     }
 
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESRequestFactory.java b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESRequestFactory.java
index 21102c83919f51e9633045de96d5ba94a4aa2b34..6b558514e7205ddeaf14cc8b631774776aefd45c 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESRequestFactory.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESRequestFactory.java
@@ -58,10 +58,6 @@ public class ESRequestFactory {
         request.source(new SearchSourceBuilder());
         request.indicesOptions(indicesOptions);
 
-        if (documentType != null) {
-            request.types(documentType);
-        }
-
         if (query != null) {
             request.source().query(query);
         }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParser.java b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParser.java
index 092892399f62f7820670f3c057665c55d11c7857..c73afbcd5fa99aaaab4e62c08e7ea53e6f1ea1cd 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParser.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParser.java
@@ -44,7 +44,7 @@ public class ESResponseParser {
         if (response == null) return null;
         SearchHits hits = response.getHits();
         if (hits == null) return null;
-        return hits.totalHits;
+        return hits.getTotalHits().value;
     }
 
     /**
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESScrollIterator.java b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESScrollIterator.java
index f106e9b7709dfc4d8e407322732e72ddd576835a..b6a070e563ebbf0dd9f86b42350674a59695ec2d 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESScrollIterator.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/ESScrollIterator.java
@@ -7,7 +7,7 @@ import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchScrollRequest;
 import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
-import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.search.sort.FieldSortBuilder;
 import org.elasticsearch.search.sort.SortOrder;
@@ -68,6 +68,13 @@ public class ESScrollIterator<T> implements Iterator<T> {
             .size(fetchSize)
             .sort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC);
 
+        // Add included and excluded fields if requested
+        String[] includedFields = documentMetadata.getIncludedFields();
+        String[] excludedFields = documentMetadata.getExcludedFields();
+        if ((includedFields != null && includedFields.length >= 1) || (excludedFields != null && excludedFields.length >= 1)) {
+            request.source().fetchSource(includedFields, excludedFields);
+        }
+
         SearchResponse response = null;
         try {
             response = client.search(request, RequestOptions.DEFAULT);
@@ -76,7 +83,7 @@ public class ESScrollIterator<T> implements Iterator<T> {
         }
 
         this.scrollId = response.getScrollId();
-        this.totalHits = response.getHits().getTotalHits();
+        this.totalHits = response.getHits().getTotalHits().value;
         this.hitIndex = 0;
         this.currentIterator = parseIterator(response);
     }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtil.java b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtil.java
index a521970d7baafc394c027314ae554af65fac1af2..eb63d3e3424b7addbbf70f1731001c94a4959d8d 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtil.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtil.java
@@ -54,8 +54,9 @@ public class DocumentAnnotationUtil {
             Map<String, DocumentMetadata.Field> fields = findDocumentFields(ImmutableList.<String>of(),
                 valueObjectClass);
 
+            String[] includedFields = document.includedFields();
             String[] excludedFields = document.excludedFields();
-            metadata = new DocumentMetadata<>(documentType, idFieldName, valueObjectClass, excludedFields, fields);
+            metadata = new DocumentMetadata<>(documentType, idFieldName, valueObjectClass, includedFields, excludedFields, fields);
             metadataCache.put(valueObjectClass, metadata);
         }
         return metadata;
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentMetadata.java b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentMetadata.java
index 6bf7389bd43b46f6dc5cd72ef5883b932788f0a5..a54e37e3c5023fcf8516a9d6e4b347ec628293da 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentMetadata.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentMetadata.java
@@ -17,15 +17,21 @@ public class DocumentMetadata<VO> {
     private final String documentType;
     private final String idField;
     private final Class<VO> documentClass;
+    private final String[] includedFields;
     private final String[] excludedFields;
     private final Map<String, Field> fieldsByName;
     private final Map<List<String>, Field> fieldByPath;
 
-    public DocumentMetadata(String documentType, String idField, Class<VO> documentClass, String[] excludedFields,
+    public DocumentMetadata(String documentType,
+                            String idField,
+                            Class<VO> documentClass,
+                            String[] includedFields,
+                            String[] excludedFields,
                             Map<String, Field> fieldsByName) {
         this.documentType = documentType;
         this.idField = idField;
         this.documentClass = documentClass;
+        this.includedFields = includedFields;
         this.excludedFields = excludedFields;
         this.fieldsByName = fieldsByName;
         this.fieldByPath = flattenDocumentFieldTree(ImmutableList.<String>of(), fieldsByName);
@@ -57,6 +63,10 @@ public class DocumentMetadata<VO> {
         return idField;
     }
 
+    public String[] getIncludedFields() {
+        return includedFields;
+    }
+
     public String[] getExcludedFields() {
         return excludedFields;
     }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/annotation/Document.java b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/annotation/Document.java
index df4af121fa9a0f84b8b90b6ec188f6f36b17bf23..3d0585a459d0fe20a030a5b2a6e88d5217dee332 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/annotation/Document.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/document/annotation/Document.java
@@ -13,5 +13,6 @@ import java.lang.annotation.Target;
 public @interface Document {
     String type();
 
+    String[] includedFields() default {};
     String[] excludedFields() default {};
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/repository/impl/ESGenericFindRepository.java b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/repository/impl/ESGenericFindRepository.java
index 54e7b287e44db289e5a83771353fc4bca487741e..e1122d86108623783ca5bf7b8d01ce3739a71796 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/repository/impl/ESGenericFindRepository.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/elasticsearch/repository/impl/ESGenericFindRepository.java
@@ -90,10 +90,11 @@ public class ESGenericFindRepository<C extends PaginationCriteria, VO> implement
             request.source().sort(field, order);
         }
 
-        // Add excluded fields if requested
+        // Add included and excluded fields if requested
+        String[] includedFields = documentMetadata.getIncludedFields();
         String[] excludedFields = documentMetadata.getExcludedFields();
-        if (excludedFields != null && excludedFields.length >= 1) {
-            request.source().fetchSource(null, excludedFields);
+        if ((includedFields != null && includedFields.length >= 1) || (excludedFields != null && excludedFields.length >= 1)) {
+            request.source().fetchSource(includedFields, excludedFields);
         }
 
         Logger logger = LoggerFactory.getLogger(ESGenericFindRepository.class);
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/filter/AngularRouteFilter.java b/backend/src/main/java/fr/inra/urgi/faidare/filter/AngularRouteFilter.java
deleted file mode 100644
index 81978e5f3bfaca602e70eff0f109477d55e1466a..0000000000000000000000000000000000000000
--- a/backend/src/main/java/fr/inra/urgi/faidare/filter/AngularRouteFilter.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package fr.inra.urgi.faidare.filter;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.ByteSource;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.*;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-
-/**
- * Filter that intercepts all request to potential Angular routes
- * (ex: /studies/ID) to send back the Angular `index.html` file with a correct
- * base href set to the spring server context path.
- *
- * Potential angular routes are devised by process of elimination:
- * - They should be GET requests
- * - They should not end with common static file suffixes {@link AngularRouteFilter#STATIC_SUFFIXES}
- * - They should not start with API prefixes {@link AngularRouteFilter#API_PREFIXES}
- *
- * <p>
- * Adapted from data-discovery
- *
- * @author gcornut
- */
-@Component
-@WebFilter("/*")
-public class AngularRouteFilter implements Filter {
-
-    private static final String[] API_PREFIXES = {
-        "/brapi/v1", "/faidare/v1", "/actuator", "/v2/api-docs", "/swagger-resources"
-    };
-
-    private static final String[] STATIC_SUFFIXES = {
-        ".html", ".js", ".css", ".ico", ".png", ".jpg", ".gif", ".eot", ".svg",
-        ".woff2", ".ttf", ".woff", ".md"
-    };
-
-    @Value("${server.servlet.context-path}")
-    private String serverContextPath;
-
-    private final ResourceLoader resourceLoader;
-
-    @Autowired
-    public AngularRouteFilter(ResourceLoader resourceLoader) {
-        this.resourceLoader = resourceLoader;
-    }
-
-    @Override
-    public void doFilter(
-        ServletRequest req,
-        ServletResponse response,
-        FilterChain chain
-    ) throws IOException, ServletException {
-        HttpServletRequest request = (HttpServletRequest) req;
-
-        if (isAngularRoute(request)) {
-            // Angular route
-            InputStream inputStream = resourceLoader.getResource("classpath:static/index.html").getInputStream();
-
-            ByteSource byteSource = new ByteSource() {
-                @Override
-                public InputStream openStream() {
-                    return inputStream;
-                }
-            };
-
-            String content = byteSource.asCharSource(Charsets.UTF_8).read();
-            String replacedContent = content.replace(
-                "<base href=\"./\">",
-                "<base href=\"" + serverContextPath + "/\">"
-            );
-            response.getWriter().write(replacedContent);
-            return;
-        }
-
-        // Otherwise nothing to do
-        chain.doFilter(request, response);
-    }
-
-    private boolean isAngularRoute(HttpServletRequest request) {
-        if (!request.getMethod().equals("GET")) {
-            return false;
-        }
-
-        String fullUri = request.getRequestURI();
-        String contextPath = request.getContextPath();
-        String uri = fullUri.substring(contextPath.length());
-
-        return !isApiOrStaticResource(uri);
-    }
-
-    private boolean isApiOrStaticResource(String relativePath) {
-        // Starts with API prefix
-        return Arrays.stream(API_PREFIXES).anyMatch(relativePath::startsWith)
-            // or has static file suffix
-            || Arrays.stream(STATIC_SUFFIXES).anyMatch(relativePath::endsWith);
-    }
-
-    @Override
-    public void init(FilterConfig filterConfig) {
-        // nothing to do
-    }
-
-    @Override
-    public void destroy() {
-        // nothing to do
-    }
-}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java
index dafff525774e979f20be09872e5357a888ed01c8..8fbd47d1273fcd733a96d6c0543bc5b1d6a133d1 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepository.java
@@ -3,6 +3,7 @@ package fr.inra.urgi.faidare.repository.es;
 import fr.inra.urgi.faidare.domain.criteria.FaidareGermplasmPOSTShearchCriteria;
 import fr.inra.urgi.faidare.domain.criteria.GermplasmSearchCriteria;
 import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.PedigreeVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.ProgenyVO;
@@ -11,6 +12,7 @@ import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.elasticsearch.repository.ESFindRepository;
 
 import java.util.Iterator;
+import java.util.Set;
 
 public interface GermplasmRepository
     extends ESFindRepository<GermplasmSearchCriteria, GermplasmVO> {
@@ -31,6 +33,11 @@ public interface GermplasmRepository
      */
     GermplasmVO getById(String germplasmDbId);
 
+    /**
+     * Scroll through all germplasms, using the given fetch size
+     */
+    Iterator<GermplasmSitemapVO> scrollAllForSitemap(int fetchSize);
+
     /**
      * Scroll through all germplasm matching the given criteria.
      */
@@ -46,6 +53,16 @@ public interface GermplasmRepository
      */
     Iterator<GermplasmMcpdVO> scrollAllGermplasmMcpd(FaidareGermplasmPOSTShearchCriteria criteria);
 
+    /**
+     * Scroll through all germplasmMcpd having one of the given IDs.
+     */
+    Iterator<GermplasmMcpdVO> scrollGermplasmMcpdsByIds(Set<String> ids, int fetchSize);
+
+    /**
+     * Scroll through all germplasm having one of the given IDs.
+     */
+    Iterator<GermplasmVO> scrollGermplasmsByIds(Set<String> ids, int fetchSize);
+
     /**
      * Find pedigree for germplasm by id.
      */
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java
index 31a6e1a8c55537fb4ffe7a35b418909c3a8dfede..2fb0677c49fe6e7d1533cf77e45efa131307df8f 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryImpl.java
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import fr.inra.urgi.faidare.domain.criteria.FaidareGermplasmPOSTShearchCriteria;
 import fr.inra.urgi.faidare.domain.criteria.GermplasmSearchCriteria;
 import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.PedigreeVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.ProgenyVO;
@@ -44,6 +45,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import static org.elasticsearch.search.aggregations.AggregationBuilders.filter;
 import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
@@ -90,6 +92,12 @@ public class GermplasmRepositoryImpl implements GermplasmRepository {
         this.criteriaMapping = AnnotatedCriteriaMapper.getMapping(criteriaClass);
     }
 
+    @Override
+    public Iterator<GermplasmSitemapVO> scrollAllForSitemap(int fetchSize) {
+        QueryBuilder query = QueryBuilders.matchAllQuery();
+        return new ESScrollIterator<>(client, requestFactory, parser, GermplasmSitemapVO.class, query, fetchSize);
+    }
+
     @Override
     public Iterator<GermplasmVO> scrollAll(GermplasmSearchCriteria criteria) {
         QueryBuilder query = queryFactory.createQuery(criteria);
@@ -111,8 +119,22 @@ public class GermplasmRepositoryImpl implements GermplasmRepository {
         return new ESScrollIterator<>(client, requestFactory, parser, GermplasmMcpdVO.class, query, fetchSize);
     }
 
+    @Override
+    public Iterator<GermplasmMcpdVO> scrollGermplasmMcpdsByIds(Set<String> ids, int fetchSize) {
+        QueryBuilder query = QueryBuilders.termsQuery("germplasmDbId", ids);
+        return new ESScrollIterator<>(client, requestFactory, parser, GermplasmMcpdVO.class, query, fetchSize);
+    }
+
+    @Override
+    public Iterator<GermplasmVO> scrollGermplasmsByIds(Set<String> ids,
+                                                       int fetchSize) {
+        QueryBuilder query = QueryBuilders.termsQuery("germplasmDbId", ids);
+        return new ESScrollIterator<>(client, requestFactory, parser, GermplasmVO.class, query, fetchSize);
+    }
+
     @Override
     public GermplasmVO getById(String germplasmDbId) {
+        //TODO getting byid is not reliable, should move to get by germplasmDbId
         return getByIdRepository.getById(germplasmDbId);
     }
 
@@ -161,7 +183,7 @@ public class GermplasmRepositoryImpl implements GermplasmRepository {
 
         LOGGER.debug("\n\nQuery from findPedigree :\n" + termQuery.toString() + "\n\n");
 
-        if (hits.totalHits == 1) {
+        if (hits.getTotalHits().value == 1) {
             // result found! \o/
             SearchHit hit = hits.getAt(0);
             String source = hit.getSourceAsString();
@@ -170,7 +192,7 @@ public class GermplasmRepositoryImpl implements GermplasmRepository {
             } catch (IOException e) {
                 LOGGER.error("Error occured when converting ES response to PedigreeVO: " + e.getMessage(), e);
             }
-        } else if (hits.totalHits > 1) {
+        } else if (hits.getTotalHits().value > 1) {
             throw new IllegalStateException("Expected only 1 result for pedigree with germplasmDbId: " + germplasmDbId);
         }
         return pedigreeVO;
@@ -190,7 +212,7 @@ public class GermplasmRepositoryImpl implements GermplasmRepository {
         final SearchHits hits = response.getHits();
         LOGGER.debug("\n\nQuery from findProgeny :\n" + termQuery.toString() + "\n\n");
 
-        if (hits.totalHits == 1) {
+        if (hits.getTotalHits().value == 1) {
             SearchHit hit = hits.getAt(0);
             String source = hit.getSourceAsString();
             try {
@@ -198,7 +220,7 @@ public class GermplasmRepositoryImpl implements GermplasmRepository {
             } catch (IOException e) {
                 LOGGER.error("Error occured when converting ES response to ProgenyVO: " + e.getMessage(), e);
             }
-        } else if (hits.totalHits > 1) {
+        } else if (hits.getTotalHits().value > 1) {
             throw new IllegalStateException("Expected only 1 result for progeny with germplasmDbId: " + germplasmDbId);
         }
         return progenyVO;
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepository.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepository.java
index 707f51bcd649768f66fdcbf99b8fee51736b5395..93e65b549079430cd2a2cfbbad8d2bb0676dd544 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepository.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepository.java
@@ -1,6 +1,9 @@
 package fr.inra.urgi.faidare.repository.es;
 
+import java.util.Iterator;
+
 import fr.inra.urgi.faidare.domain.criteria.LocationCriteria;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
 import fr.inra.urgi.faidare.domain.data.LocationVO;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.elasticsearch.repository.ESFindRepository;
@@ -21,4 +24,5 @@ public interface LocationRepository
     @Override
     PaginatedList<LocationVO> find(LocationCriteria criteria);
 
+    Iterator<LocationSitemapVO> scrollAllForSitemap(int fetchSize);
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryImpl.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryImpl.java
index af74a55c2e7f9cf7e788e3905186a2bef9a66182..0a1133d75f654527a74a2bad73bc21a83763e52c 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryImpl.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryImpl.java
@@ -1,11 +1,18 @@
 package fr.inra.urgi.faidare.repository.es;
 
+import java.util.Iterator;
+
 import fr.inra.urgi.faidare.domain.criteria.LocationCriteria;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
 import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
 import fr.inra.urgi.faidare.elasticsearch.ESRequestFactory;
 import fr.inra.urgi.faidare.elasticsearch.ESResponseParser;
+import fr.inra.urgi.faidare.elasticsearch.ESScrollIterator;
 import fr.inra.urgi.faidare.elasticsearch.repository.impl.BaseESRepository;
 import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 
@@ -17,6 +24,10 @@ public class LocationRepositoryImpl
     extends BaseESRepository<LocationCriteria, LocationVO>
     implements LocationRepository {
 
+    private final RestHighLevelClient client;
+    private final ESRequestFactory requestFactory;
+    private final ESResponseParser parser;
+
     @Autowired
     public LocationRepositoryImpl(
         RestHighLevelClient client,
@@ -24,6 +35,14 @@ public class LocationRepositoryImpl
         ESResponseParser parser
     ) {
         super(client, requestFactory, LocationVO.class, parser);
+        this.client = client;
+        this.requestFactory = requestFactory;
+        this.parser = parser;
     }
 
+    @Override
+    public Iterator<LocationSitemapVO> scrollAllForSitemap(int fetchSize) {
+        QueryBuilder query = QueryBuilders.matchAllQuery();
+        return new ESScrollIterator<>(client, requestFactory, parser, LocationSitemapVO.class, query, fetchSize);
+    }
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepository.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepository.java
index 6ceeca9f655fea5b94548d3c32941906c976d625..8831a8c1ff66f6a31aeac3825d690651da10c27b 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepository.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepository.java
@@ -1,12 +1,15 @@
 package fr.inra.urgi.faidare.repository.es;
 
 import fr.inra.urgi.faidare.domain.criteria.StudyCriteria;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
 import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
+import fr.inra.urgi.faidare.domain.data.study.StudySitemapVO;
 import fr.inra.urgi.faidare.domain.data.study.StudySummaryVO;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.elasticsearch.repository.ESFindRepository;
 import fr.inra.urgi.faidare.elasticsearch.repository.ESGetByIdRepository;
 
+import java.util.Iterator;
 import java.util.Set;
 
 /**
@@ -29,4 +32,5 @@ public interface StudyRepository
      */
     Set<String> getVariableIds(String studyDbId);
 
+    Iterator<StudySitemapVO> scrollAllForSitemap(int fetchSize);
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryImpl.java b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryImpl.java
index d9410a871cb1c7c0f9ab3966594b523fe6d29b3b..46b0b71248b4a5498a9d24bedb3f854ce756af6f 100644
--- a/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryImpl.java
+++ b/backend/src/main/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryImpl.java
@@ -2,12 +2,15 @@ package fr.inra.urgi.faidare.repository.es;
 
 import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiLocation;
 import fr.inra.urgi.faidare.domain.criteria.StudyCriteria;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
 import fr.inra.urgi.faidare.domain.data.LocationVO;
 import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
+import fr.inra.urgi.faidare.domain.data.study.StudySitemapVO;
 import fr.inra.urgi.faidare.domain.data.study.StudySummaryVO;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.elasticsearch.ESRequestFactory;
 import fr.inra.urgi.faidare.elasticsearch.ESResponseParser;
+import fr.inra.urgi.faidare.elasticsearch.ESScrollIterator;
 import fr.inra.urgi.faidare.elasticsearch.document.DocumentAnnotationUtil;
 import fr.inra.urgi.faidare.elasticsearch.document.DocumentMetadata;
 import fr.inra.urgi.faidare.elasticsearch.query.impl.ESGenericQueryFactory;
@@ -19,6 +22,8 @@ import org.elasticsearch.action.search.SearchRequest;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
 import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
 import org.slf4j.Logger;
@@ -28,6 +33,7 @@ import org.springframework.stereotype.Repository;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -129,4 +135,9 @@ public class StudyRepositoryImpl
         return new LinkedHashSet<>(ids);
     }
 
+    @Override
+    public Iterator<StudySitemapVO> scrollAllForSitemap(int fetchSize) {
+        QueryBuilder query = QueryBuilders.matchAllQuery();
+        return new ESScrollIterator<>(client, requestFactory, parser, StudySitemapVO.class, query, fetchSize);
+    }
 }
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/utils/Sitemaps.java b/backend/src/main/java/fr/inra/urgi/faidare/utils/Sitemaps.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba32b8cf286c1c04b589e50a4338addae9df2e78
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/utils/Sitemaps.java
@@ -0,0 +1,125 @@
+package fr.inra.urgi.faidare.utils;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
+/**
+ * A generator of site maps.
+ * @author JB Nizet
+ */
+@Component
+public class Sitemaps {
+    public static final int BUCKET_COUNT = 11;
+
+    public static <T> void generateSitemap(String sitemapPath,
+                                           OutputStream out,
+                                           Iterator<T> entryIterator,
+                                           Predicate<T> entryPredicate,
+                                           Function<T, String> entryToPath) {
+        SanityChecker sanityChecker = new SanityChecker(sitemapPath);
+
+        Writer writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
+        Stream<T> entries =
+            StreamSupport.stream(Spliterators.spliteratorUnknownSize(entryIterator, 0), false);
+        entries.filter(entryPredicate)
+               .map(entryToPath)
+               .map(entryPath -> Sitemaps.generateSitemapUrl(entryPath) + '\n')
+               .forEach(entry -> {
+                   try {
+                       writer.write(entry);
+                       sanityChecker.addEntry(entry);
+                   }
+                   catch (IOException e) {
+                       throw new UncheckedIOException(e);
+                   }
+               });
+
+        try {
+            writer.flush();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+
+        sanityChecker.check();
+    }
+
+    public static String generateSitemapUrl(String path) {
+        return ServletUriComponentsBuilder
+            .fromCurrentContextPath()
+            .path(path)
+            .toUriString();
+    }
+
+    private static class SanityChecker {
+        private static final Logger LOGGER = LoggerFactory.getLogger(SanityChecker.class);
+
+        private static final int MAX_ENTRY_COUNT = 50_000;
+        private static final int MAX_BYTE_COUNT = 50 * 1024 * 1024;
+
+        private static final int DANGER_ENTRY_COUNT = 40_000;
+        private static final int DANGER_BYTE_COUNT = 40 * 1024 * 1024;
+
+        private final String sitemapPath;
+        private int entryCount = 0;
+        private int byteCount = 0;
+
+        public SanityChecker(String sitemapPath) {
+            this.sitemapPath = sitemapPath;
+        }
+
+        public void addEntry(String entry) {
+            entryCount++;
+            byteCount += entry.length();
+        }
+
+        public void check() {
+            if (entryCount > MAX_ENTRY_COUNT) {
+                LOGGER.error("The generated sitemap at path "
+                                 + sitemapPath +
+                                 " has more than "
+                                 + MAX_ENTRY_COUNT +
+                                 " entries and will thus be rejected by search engines. Increase Sitemaps.BUCKET_COUNT for a better distribution of sitemap entries.");
+            } else if (entryCount > DANGER_ENTRY_COUNT) {
+                LOGGER.warn("The generated sitemap at path "
+                                + sitemapPath
+                                + " has more than "
+                                + DANGER_ENTRY_COUNT
+                                + " entries and is thus approaching the max of "
+                                + MAX_ENTRY_COUNT
+                                + ". Increase Sitemaps.BUCKET_COUNT for a better distribution of sitemap entries.");
+            }
+
+            if (byteCount > MAX_BYTE_COUNT) {
+                LOGGER.error("The generated sitemap at path "
+                                 + sitemapPath
+                                 + " has more than "
+                                 + MAX_BYTE_COUNT
+                                 + " bytes and will thus be rejected by search engines. Increase Sitemaps.BUCKET_COUNT for a better distribution of sitemap entries.");
+            } else if (entryCount > DANGER_ENTRY_COUNT) {
+                LOGGER.warn("The generated sitemap at path "
+                                + sitemapPath
+                                + " has more than "
+                                + DANGER_BYTE_COUNT
+                                + " bytes and is thus approaching the max of "
+                                + MAX_BYTE_COUNT
+                                + ". Increase Sitemaps.BUCKET_COUNT for a better distribution of sitemap entries.");
+            }
+        }
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/utils/Sites.java b/backend/src/main/java/fr/inra/urgi/faidare/utils/Sites.java
new file mode 100644
index 0000000000000000000000000000000000000000..1cab28c4502f53fa7774f8ac2f4d3eca477b8fa8
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/utils/Sites.java
@@ -0,0 +1,14 @@
+package fr.inra.urgi.faidare.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+/**
+ * Utilities for sites
+ * @author JB Nizet
+ */
+public class Sites {
+    public static String siteIdToLocationId(String siteId) {
+        return Base64.getUrlEncoder().encodeToString(("urn:INRAE-URGI/location/" + siteId).getBytes(StandardCharsets.US_ASCII));
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/HomeController.java b/backend/src/main/java/fr/inra/urgi/faidare/web/HomeController.java
new file mode 100644
index 0000000000000000000000000000000000000000..6734b6aa97a2ae445af4eb61be86a07883b2a58a
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/HomeController.java
@@ -0,0 +1,19 @@
+package fr.inra.urgi.faidare.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * Controller for the home page, which doesn't display much
+ * @author JB Nizet
+ */
+@Controller
+@RequestMapping("")
+public class HomeController {
+    @GetMapping
+    public ModelAndView home() {
+        return new ModelAndView("index");
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmController.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmController.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc3b1b85cccec18f4c32149885acbffe0ba690dc
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmController.java
@@ -0,0 +1,241 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import fr.inra.urgi.faidare.api.NotFoundException;
+import fr.inra.urgi.faidare.config.FaidareProperties;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiGermplasmAttributeValue;
+import fr.inra.urgi.faidare.domain.criteria.GermplasmAttributeCriteria;
+import fr.inra.urgi.faidare.domain.criteria.GermplasmGETSearchCriteria;
+import fr.inra.urgi.faidare.domain.data.germplasm.CollPopVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.PedigreeVO;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentSearchCriteria;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.repository.es.GermplasmAttributeRepository;
+import fr.inra.urgi.faidare.repository.es.GermplasmRepository;
+import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
+import fr.inra.urgi.faidare.utils.Sitemaps;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
+
+/**
+ * Controller used to display a germplasm card based on its ID.
+ * Note that this controller is mapped to the /germplasm path in addition to
+ * the canonical /germplasms path in order to still honor legacy URLs used
+ * in external applications
+ * @author JB Nizet
+ */
+@Controller("webGermplasmController")
+@RequestMapping({"/germplasms", "/germplasm"})
+public class GermplasmController {
+
+    private final GermplasmRepository germplasmRepository;
+    private final FaidareProperties faidareProperties;
+    private final XRefDocumentRepository xRefDocumentRepository;
+    private final GermplasmAttributeRepository germplasmAttributeRepository;
+    private final GermplasmMcpdExportService germplasmMcpdExportService;
+    private final GermplasmExportService germplasmExportService;
+
+    public GermplasmController(GermplasmRepository germplasmRepository,
+                               FaidareProperties faidareProperties,
+                               XRefDocumentRepository xRefDocumentRepository,
+                               GermplasmAttributeRepository germplasmAttributeRepository,
+                               GermplasmMcpdExportService germplasmMcpdExportService,
+                               GermplasmExportService germplasmExportService) {
+        this.germplasmRepository = germplasmRepository;
+        this.faidareProperties = faidareProperties;
+        this.xRefDocumentRepository = xRefDocumentRepository;
+        this.germplasmAttributeRepository = germplasmAttributeRepository;
+        this.germplasmMcpdExportService = germplasmMcpdExportService;
+        this.germplasmExportService = germplasmExportService;
+    }
+
+    @GetMapping("/{germplasmId}")
+    public ModelAndView get(@PathVariable("germplasmId") String germplasmId) {
+        GermplasmVO germplasm = germplasmRepository.getById(germplasmId);
+
+        if (germplasm == null) {
+            throw new NotFoundException("Germplasm with ID " + germplasmId + " not found");
+        }
+
+        return toModelAndView(germplasm);
+    }
+
+    @GetMapping(params = "id")
+    public ModelAndView getById(@RequestParam("id") String germplasmId) {
+        GermplasmVO germplasm = germplasmRepository.getById(germplasmId);
+
+        if (germplasm == null) {
+            throw new NotFoundException("Germplasm with ID " + germplasmId + " not found");
+        }
+
+        return toModelAndView(germplasm);
+    }
+
+    @GetMapping(params = "pui")
+    public ModelAndView getByPui(@RequestParam("pui") String pui) {
+        GermplasmGETSearchCriteria criteria = new GermplasmGETSearchCriteria();
+        criteria.setGermplasmPUI(Collections.singletonList(pui));
+        List<GermplasmVO> germplasms = germplasmRepository.find(criteria);
+        if (germplasms.size() != 1) {
+            throw new NotFoundException("Germplasm with PUI " + pui + " not found");
+        }
+
+        return toModelAndView(germplasms.get(0));
+    }
+
+    @PostMapping("/exports/mcpd")
+    @ResponseBody
+    public ResponseEntity<StreamingResponseBody> export(@Validated @RequestBody GermplasmMcpdExportCommand command) {
+        List<GermplasmMcpdExportableField> fields = getFieldsToExport(command);
+
+        StreamingResponseBody body = out -> {
+            Iterator<GermplasmMcpdVO> iterator = germplasmRepository.scrollGermplasmMcpdsByIds(command.getIds(), 1000);
+            germplasmMcpdExportService.export(out, iterator, fields);
+        };
+        return ResponseEntity.ok().contentType(MediaType.parseMediaType("text/csv")).body(body);
+    }
+
+    @PostMapping("/exports/plant-material")
+    @ResponseBody
+    public ResponseEntity<StreamingResponseBody> export(@Validated @RequestBody GermplasmExportCommand command) {
+        List<GermplasmExportableField> fields = getFieldsToExport(command);
+
+        StreamingResponseBody body = out -> {
+            Iterator<GermplasmVO> iterator = germplasmRepository.scrollGermplasmsByIds(command.getIds(), 1000);
+            germplasmExportService.export(out, iterator, fields);
+        };
+        return ResponseEntity.ok().contentType(MediaType.parseMediaType("text/csv")).body(body);
+    }
+
+    @GetMapping("/sitemap-{index}.txt")
+    @ResponseBody
+    public ResponseEntity<StreamingResponseBody> sitemap(@PathVariable("index") int index) {
+        if (index < 0 || index >= Sitemaps.BUCKET_COUNT) {
+            throw new NotFoundException("no sitemap for this index");
+        }
+        StreamingResponseBody body = out -> {
+            Iterator<GermplasmSitemapVO> iterator = germplasmRepository.scrollAllForSitemap(1000);
+            Sitemaps.generateSitemap(
+                "/germplasms/sitemap-" + index + ".txt",
+                out,
+                iterator,
+                vo -> Math.floorMod(vo.getGermplasmDbId().hashCode(), Sitemaps.BUCKET_COUNT) == index,
+                vo -> "/germplasms/" + vo.getGermplasmDbId()
+            );
+        };
+        return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(body);
+    }
+
+    private ModelAndView toModelAndView(GermplasmVO germplasm) {
+        List<BrapiGermplasmAttributeValue> attributes = getAttributes(germplasm);
+        PedigreeVO pedigree = getPedigree(germplasm);
+
+        List<XRefDocumentVO> crossReferences = xRefDocumentRepository.find(
+            XRefDocumentSearchCriteria.forXRefId(germplasm.getGermplasmDbId())
+        );
+
+        sortDonors(germplasm);
+        sortPopulations(germplasm);
+        sortCollections(germplasm);
+        sortPanels(germplasm);
+        return new ModelAndView("germplasm",
+                                "model",
+                                new GermplasmModel(
+                                    germplasm,
+                                    faidareProperties.getByUri(germplasm.getSourceUri()),
+                                    attributes,
+                                    pedigree,
+                                    crossReferences)
+        );
+    }
+
+    private void sortPopulations(GermplasmVO germplasm) {
+        if (germplasm.getPopulation() != null) {
+            germplasm.setPopulation(germplasm.getPopulation()
+                                             .stream()
+                                             .sorted(Comparator.comparing(
+                                                 CollPopVO::getName))
+                                             .collect(Collectors.toList()));
+        }
+    }
+
+    private void sortCollections(GermplasmVO germplasm) {
+        if (germplasm.getCollection() != null) {
+            germplasm.setCollection(germplasm.getCollection()
+                                             .stream()
+                                             .sorted(Comparator.comparing(CollPopVO::getName))
+                                             .collect(Collectors.toList()));
+        }
+    }
+
+    private void sortPanels(GermplasmVO germplasm) {
+        if (germplasm.getPanel() != null) {
+            germplasm.setPanel(germplasm.getPanel()
+                                        .stream()
+                                        .sorted(Comparator.comparing(CollPopVO::getName))
+                                        .collect(Collectors.toList()));
+        }
+    }
+
+    private void sortDonors(GermplasmVO germplasm) {
+        if (germplasm.getDonors() != null) {
+            germplasm.setDonors(germplasm.getDonors()
+                                         .stream()
+                                         .sorted(Comparator.comparing(donor -> donor.getDonorInstitute()
+                                                                                    .getInstituteName()))
+                                         .collect(Collectors.toList()));
+        }
+    }
+
+    private List<BrapiGermplasmAttributeValue> getAttributes(GermplasmVO germplasm) {
+        GermplasmAttributeCriteria criteria = new GermplasmAttributeCriteria();
+        criteria.setGermplasmDbId(germplasm.getGermplasmDbId());
+        return germplasmAttributeRepository.find(criteria)
+            .stream()
+            .flatMap(vo -> vo.getData().stream())
+            .sorted(Comparator.comparing(BrapiGermplasmAttributeValue::getAttributeName))
+            .collect(Collectors.toList());
+    }
+
+    private PedigreeVO getPedigree(GermplasmVO germplasm) {
+        return germplasmRepository.findPedigree(germplasm.getGermplasmDbId());
+    }
+
+    private List<GermplasmMcpdExportableField> getFieldsToExport(
+        GermplasmMcpdExportCommand command) {
+        List<GermplasmMcpdExportableField> fields = command.getFields();
+        if (fields.isEmpty()) {
+            fields = Arrays.asList(GermplasmMcpdExportableField.values());
+        }
+        return fields;
+    }
+
+    private List<GermplasmExportableField> getFieldsToExport(
+        GermplasmExportCommand command) {
+        List<GermplasmExportableField> fields = command.getFields();
+        if (fields.isEmpty()) {
+            fields = Arrays.asList(GermplasmExportableField.values());
+        }
+        return fields;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportCommand.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ae02bdf4f7fdab3a8bf66ef35d583b863ef39f0
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportCommand.java
@@ -0,0 +1,39 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.validation.constraints.NotEmpty;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Command sent to export a list of germplasm IDs
+ * @author JB Nizet
+ */
+public class GermplasmExportCommand {
+
+    @NotEmpty
+    private final Set<String> ids;
+
+    /**
+     * The ordered list of fields to export. If empty, all fields are exported
+     */
+    private final List<GermplasmExportableField> fields;
+
+    @JsonCreator
+    public GermplasmExportCommand(@JsonProperty("ids") Set<String> ids,
+                                  @JsonProperty("fields") List<GermplasmExportableField> fields) {
+        this.ids = ids;
+        this.fields = fields == null ? Collections.emptyList() : fields;
+    }
+
+    public Set<String> getIds() {
+        return ids;
+    }
+
+    public List<GermplasmExportableField> getFields() {
+        return fields;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportService.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf0919015e97a6336f422e4ab7a145766cf5157d
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportService.java
@@ -0,0 +1,101 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import static fr.inra.urgi.faidare.web.germplasm.GermplasmExportableField.*;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import com.opencsv.CSVWriter;
+import fr.inra.urgi.faidare.domain.data.germplasm.CollPopVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import org.springframework.stereotype.Component;
+
+/**
+ * Service allowing to export germplasms as CSV
+ * @author JB Nizet
+ */
+@Component
+public class GermplasmExportService {
+
+    private final Map<GermplasmExportableField, GermplasmExportableFieldDescriptor> descriptors;
+
+    public GermplasmExportService() {
+        Map<GermplasmExportableField, GermplasmExportableFieldDescriptor> map = new HashMap<>();
+
+        map.put(DOI, new GermplasmExportableFieldDescriptor("DOI", vo -> vo.getGermplasmPUI()));
+        map.put(ACCESSION_NUMBER, new GermplasmExportableFieldDescriptor("Accession number", vo -> vo.getAccessionNumber()));
+        map.put(ACCESSION_NAME, new GermplasmExportableFieldDescriptor("Accession name", vo -> vo.getGermplasmName()));
+        map.put(TAXON_GROUP, new GermplasmExportableFieldDescriptor("Taxon group", vo -> vo.getCommonCropName()));
+        map.put(HOLDING_INSTITUTION, new GermplasmExportableFieldDescriptor("Holding institution", vo -> vo.getInstituteName()));
+        map.put(LOT_NAME, new GermplasmExportableFieldDescriptor("Lot name", vo -> null));
+        map.put(LOT_SYNONYM, new GermplasmExportableFieldDescriptor("Lot synonym", vo -> null));
+        map.put(COLLECTION_NAME, new GermplasmExportableFieldDescriptor("Collection name", vo -> (vo.getCollection() == null ) ? null : vo.getCollection().stream().map(
+            CollPopVO::getName).collect(Collectors.joining(", "))));
+        map.put(COLLECTION_TYPE, new GermplasmExportableFieldDescriptor("Collection type", vo -> null));
+        map.put(PANEL_NAME, new GermplasmExportableFieldDescriptor("Panel name", vo -> (vo.getPanel() == null)? null : vo.getPanel().stream().map(CollPopVO::getName).collect(
+            Collectors.joining(", "))));
+        map.put(PANEL_SIZE, new GermplasmExportableFieldDescriptor("Panel size", vo -> null));
+
+        this.descriptors = Collections.unmodifiableMap(map);
+        if (map.size() != GermplasmExportableField.values().length) {
+            throw new IllegalStateException("Missing field descriptor");
+        }
+    }
+
+    public void export(OutputStream out, Iterator<GermplasmVO> germplasms, List<GermplasmExportableField> fields) {
+        try {
+            CSVWriter csvWriter = new CSVWriter(new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)), ';', '"', '\\', "\n");
+            String[] header = fields.stream()
+                                    .map(descriptors::get)
+                                    .map(GermplasmExportableFieldDescriptor::getHeader)
+                                    .toArray(String[]::new);
+            csvWriter.writeNext(header);
+
+            while (germplasms.hasNext()) {
+                GermplasmVO vo = germplasms.next();
+                String[] line =
+                    fields.stream()
+                          .map(descriptors::get)
+                          .map(descriptor -> descriptor.export(vo))
+                          .toArray(String[]::new);
+                csvWriter.writeNext(line);
+            }
+            csvWriter.flush();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private static class GermplasmExportableFieldDescriptor {
+        private final String header;
+        private final Function<GermplasmVO, String> exporter;
+
+        public GermplasmExportableFieldDescriptor(String header,
+                                                  Function<GermplasmVO, String> exporter) {
+            this.header = header;
+            this.exporter = exporter;
+        }
+
+        public String getHeader() {
+            return this.header;
+        }
+
+        public String export(GermplasmVO germplasm) {
+            return this.exporter.apply(germplasm);
+        }
+    }
+}
+
+
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportableField.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportableField.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecda40cbcdd5fb14532d9b4d9f37eb09b85d90ae
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmExportableField.java
@@ -0,0 +1,20 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+/**
+ * The fields of a germplasm that can be exported
+ *
+ * @author JB Nizet
+ */
+public enum GermplasmExportableField {
+    DOI,
+    ACCESSION_NUMBER,
+    ACCESSION_NAME,
+    TAXON_GROUP,
+    HOLDING_INSTITUTION,
+    LOT_NAME,
+    LOT_SYNONYM,
+    COLLECTION_NAME,
+    COLLECTION_TYPE,
+    PANEL_NAME,
+    PANEL_SIZE
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportCommand.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..deefb113622f13aa13c55187b2f61a16b96ac041
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportCommand.java
@@ -0,0 +1,39 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.validation.constraints.NotEmpty;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Command sent to export a list of germplasm MCPD IDs
+ * @author JB Nizet
+ */
+public class GermplasmMcpdExportCommand {
+
+    @NotEmpty
+    private final Set<String> ids;
+
+    /**
+     * The ordered list of fields to export. If empty, all fields are exported
+     */
+    private final List<GermplasmMcpdExportableField> fields;
+
+    @JsonCreator
+    public GermplasmMcpdExportCommand(@JsonProperty("ids") Set<String> ids,
+                                      @JsonProperty("fields") List<GermplasmMcpdExportableField> fields) {
+        this.ids = ids;
+        this.fields = fields == null ? Collections.emptyList() : fields;
+    }
+
+    public Set<String> getIds() {
+        return ids;
+    }
+
+    public List<GermplasmMcpdExportableField> getFields() {
+        return fields;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportService.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..3861ab09c032bb186258c09ed05e3a40086a515b
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportService.java
@@ -0,0 +1,167 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import static fr.inra.urgi.faidare.web.germplasm.GermplasmMcpdExportableField.*;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import com.opencsv.CSVWriter;
+import fr.inra.urgi.faidare.domain.data.germplasm.DonorInfoVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.InstituteVO;
+import org.springframework.stereotype.Component;
+
+/**
+ * Service allowing to export germplasm MCPDs as CSV
+ * @author JB Nizet
+ */
+@Component
+public class GermplasmMcpdExportService {
+
+    private final Map<GermplasmMcpdExportableField, GermplasmMcpdExportableFieldDescriptor> descriptors;
+
+    public GermplasmMcpdExportService() {
+        Map<GermplasmMcpdExportableField, GermplasmMcpdExportableFieldDescriptor> map = new HashMap<>();
+
+        map.put(PUID, withFieldAsHeader(PUID, vo -> vo.getGermplasmPUI()));
+        map.put(INSTCODE, withFieldAsHeader(INSTCODE, vo -> vo.getInstituteCode()));
+        map.put(ACCENUMB, withFieldAsHeader(ACCENUMB, vo -> vo.getAccessionNumber()));
+        map.put(COLLNUMB, withFieldAsHeader(COLLNUMB, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingNumber()));
+        map.put(COLLCODE, withFieldAsHeader(COLLCODE, vo -> (vo.getCollectingInfo() == null)? null :
+            vo.getCollectingInfo()
+              .getCollectingInstitutes()
+              .stream()
+              .map(InstituteVO::getInstituteCode).collect(Collectors.joining(";"))));
+        map.put(COLLNAME, withFieldAsHeader(COLLNAME, vo -> (vo.getCollectingInfo() == null)? null :
+            vo.getCollectingInfo()
+              .getCollectingInstitutes()
+              .stream()
+              .map(InstituteVO::getInstituteName)
+              .collect(Collectors.joining(";"))));
+        map.put(COLLINSTADDRESS, withFieldAsHeader(COLLINSTADDRESS, vo -> (vo.getCollectingInfo() == null || vo.getCollectingInfo().getCollectingInstitutes() == null)? null :
+            vo.getCollectingInfo()
+              .getCollectingInstitutes()
+              .stream()
+              .map(InstituteVO::getAddress)
+              .collect(Collectors.joining(";"))));
+        map.put(COLLMISSID, withFieldAsHeader(COLLMISSID, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingMissionIdentifier()));
+        map.put(GENUS, withFieldAsHeader(GENUS, vo -> vo.getGenus()));
+        map.put(SPECIES, withFieldAsHeader(SPECIES, vo -> vo.getSpecies()));
+        map.put(SPAUTHOR, withFieldAsHeader(SPAUTHOR, vo -> vo.getSpeciesAuthority()));
+        map.put(SUBTAXA, withFieldAsHeader(SUBTAXA, vo -> vo.getSubtaxon()));
+        map.put(SUBTAUTHOR, withFieldAsHeader(SUBTAUTHOR, vo -> vo.getSubtaxonAuthority()));
+        map.put(CROPNAME, withFieldAsHeader(CROPNAME, vo -> vo.getCommonCropName()));
+        map.put(ACCENAME, withFieldAsHeader(ACCENAME, vo -> String.join(";", vo.getAccessionNames())));
+        map.put(ACQDATE, withFieldAsHeader(ACQDATE, vo -> vo.getAcquisitionDate()));
+        map.put(ORIGCTY, withFieldAsHeader(ORIGCTY, vo -> vo.getCountryOfOriginCode()));
+        map.put(COLLSITE, withFieldAsHeader(COLLSITE, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getSiteName()));
+        map.put(DECLATITUDE, withFieldAsHeader(DECLATITUDE, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getLatitudeDecimal()));
+        map.put(LATITUDE, withFieldAsHeader(LATITUDE, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getLatitudeDegrees()));
+        map.put(DECLONGITUDE, withFieldAsHeader(DECLONGITUDE, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getLongitudeDecimal()));
+        map.put(LONGITUDE, withFieldAsHeader(LONGITUDE, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getLongitudeDegrees()));
+        map.put(COORDUNCERT, withFieldAsHeader(COORDUNCERT, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getCoordinateUncertainty()));
+        map.put(COORDDATUM, withFieldAsHeader(COORDDATUM, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getSpatialReferenceSystem()));
+        map.put(GEOREFMETH, withFieldAsHeader(GEOREFMETH, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getGeoreferencingMethod()));
+        map.put(ELEVATION, withFieldAsHeader(ELEVATION, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingSite().getElevation()));
+        map.put(COLLDATE, withFieldAsHeader(COLLDATE, vo -> (vo.getCollectingInfo() == null)? null : vo.getCollectingInfo().getCollectingDate()));
+        map.put(BREDCODE, withFieldAsHeader(BREDCODE, vo -> (vo.getBreedingInstitutes() == null)? null :
+            vo.getBreedingInstitutes()
+              .stream()
+              .map(InstituteVO::getInstituteCode)
+              .collect(Collectors.joining(";"))));
+        map.put(BREDNAME, withFieldAsHeader(BREDNAME, vo -> (vo.getBreedingInstitutes() == null)? null :
+            vo.getBreedingInstitutes()
+              .stream()
+              .map(InstituteVO::getInstituteName)
+              .collect(Collectors.joining(";"))));
+        map.put(SAMPSTAT, withFieldAsHeader(SAMPSTAT, vo -> vo.getBiologicalStatusOfAccessionCode()));
+        map.put(ANCEST, withFieldAsHeader(ANCEST, vo -> vo.getAncestralData()));
+        map.put(COLLSRC, withFieldAsHeader(COLLSRC, vo -> vo.getAcquisitionSourceCode()));
+        map.put(DONORCODE, withFieldAsHeader(DONORCODE, vo -> (vo.getDonorInfo() == null )? null :
+            vo.getDonorInfo()
+              .stream()
+              .map(donorInfoVO -> donorInfoVO.getDonorInstitute().getInstituteCode())
+              .collect(Collectors.joining(";"))));
+        map.put(DONORNAME, withFieldAsHeader(DONORNAME, vo -> (vo.getDonorInfo() == null)? null :
+            vo.getDonorInfo()
+              .stream()
+              .map(donorInfoVO -> donorInfoVO.getDonorInstitute().getInstituteName())
+              .collect(Collectors.joining(";"))));
+        map.put(DONORNUMB, withFieldAsHeader(DONORNUMB, vo -> (vo.getDonorInfo() == null )? null :
+            vo.getDonorInfo()
+              .stream()
+              .map(DonorInfoVO::getDonorAccessionNumber)
+              .collect(Collectors.joining(";"))));
+        map.put(OTHERNUMB, withFieldAsHeader(OTHERNUMB, vo -> String.join(";", vo.getAlternateIDs())));
+        map.put(MLSSTAT, withFieldAsHeader(MLSSTAT, vo -> vo.getMlsStatus()));
+        map.put(REMARKS, withFieldAsHeader(REMARKS, vo -> vo.getRemarks()));
+
+        this.descriptors = Collections.unmodifiableMap(map);
+
+       /* if (map.size() != GermplasmMcpdExportableField.values().length) {
+            throw new IllegalStateException("Missing field descriptor");
+        }*/
+    }
+
+    public void export(OutputStream out, Iterator<GermplasmMcpdVO> germplasms, List<GermplasmMcpdExportableField> fields) {
+        try {
+            CSVWriter csvWriter = new CSVWriter(new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)), ';', '"', '\\', "\n");
+            String[] header = fields.stream()
+                                    .map(descriptors::get)
+                                    .map(GermplasmMcpdExportableFieldDescriptor::getHeader)
+                                    .toArray(String[]::new);
+            csvWriter.writeNext(header);
+
+            while (germplasms.hasNext()) {
+                GermplasmMcpdVO vo = germplasms.next();
+                String[] line =
+                    fields.stream()
+                          .map(descriptors::get)
+                          .map(descriptor -> descriptor.export(vo))
+                          .toArray(String[]::new);
+                csvWriter.writeNext(line);
+            }
+            csvWriter.flush();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private GermplasmMcpdExportableFieldDescriptor withFieldAsHeader(
+        GermplasmMcpdExportableField field,
+        Function<GermplasmMcpdVO, String> exporter) {
+        return new GermplasmMcpdExportableFieldDescriptor(field.name(), exporter);
+    }
+
+    private static class GermplasmMcpdExportableFieldDescriptor {
+        private final String header;
+        private final Function<GermplasmMcpdVO, String> exporter;
+
+        public GermplasmMcpdExportableFieldDescriptor(String header,
+                                                      Function<GermplasmMcpdVO, String> exporter) {
+            this.header = header;
+            this.exporter = exporter;
+        }
+
+        public String getHeader() {
+            return this.header;
+        }
+
+        public String export(GermplasmMcpdVO germplasm) {
+            return this.exporter.apply(germplasm);
+        }
+    }
+}
+
+
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportableField.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportableField.java
new file mode 100644
index 0000000000000000000000000000000000000000..eda85e1fa243ffc71a05c449dc9c7e153b19f97a
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmMcpdExportableField.java
@@ -0,0 +1,49 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * The fields of a germplasm MCPD that can be exported
+ *
+ * @author JB Nizet
+ */
+public enum GermplasmMcpdExportableField {
+    PUID,
+    INSTCODE,
+    ACCENUMB,
+    COLLNUMB,
+    COLLCODE,
+    COLLNAME,
+    COLLINSTADDRESS,
+    COLLMISSID,
+    GENUS,
+    SPECIES,
+    SPAUTHOR,
+    SUBTAXA,
+    SUBTAUTHOR,
+    CROPNAME,
+    ACCENAME,
+    ACQDATE,
+    ORIGCTY,
+    COLLSITE,
+    DECLATITUDE,
+    LATITUDE,
+    DECLONGITUDE,
+    LONGITUDE,
+    COORDUNCERT,
+    COORDDATUM,
+    GEOREFMETH,
+    ELEVATION,
+    COLLDATE,
+    BREDCODE,
+    BREDNAME,
+    SAMPSTAT,
+    ANCEST,
+    COLLSRC,
+    DONORCODE,
+    DONORNAME,
+    DONORNUMB,
+    OTHERNUMB,
+    MLSSTAT,
+    REMARKS
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmModel.java b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..da82e8097c1ef1b52949ffe3def70b3d8ea41f16
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/germplasm/GermplasmModel.java
@@ -0,0 +1,162 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiGermplasmAttributeValue;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmInstituteVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.PedigreeVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.SiteVO;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.web.site.MapLocation;
+import org.springframework.util.StringUtils;
+
+/**
+ * The model used by the germplasm page
+ * @author JB Nizet
+ */
+public final class GermplasmModel {
+    private final GermplasmVO germplasm;
+    private final DataSource source;
+    private final List<BrapiGermplasmAttributeValue> attributes;
+    private final PedigreeVO pedigree;
+    private final List<XRefDocumentVO> crossReferences;
+
+    public GermplasmModel(GermplasmVO germplasm,
+                          DataSource source,
+                          List<BrapiGermplasmAttributeValue> attributes,
+                          PedigreeVO pedigree,
+                          List<XRefDocumentVO> crossReferences) {
+        this.germplasm = germplasm;
+        this.source = source;
+        this.attributes = attributes;
+        this.pedigree = pedigree;
+        this.crossReferences = crossReferences;
+    }
+
+    public GermplasmVO getGermplasm() {
+        return germplasm;
+    }
+
+    public DataSource getSource() {
+        return source;
+    }
+
+    public List<BrapiGermplasmAttributeValue> getAttributes() {
+        return attributes;
+    }
+
+    public PedigreeVO getPedigree() {
+        return pedigree;
+    }
+
+    public List<XRefDocumentVO> getCrossReferences() {
+        return crossReferences;
+    }
+
+    public String getTaxon() {
+        if (StringUtils.hasText(this.germplasm.getGenusSpeciesSubtaxa())) {
+            return this.germplasm.getGenusSpeciesSubtaxa();
+        } else if (StringUtils.hasText(this.germplasm.getGenusSpecies())) {
+            return this.germplasm.getGenusSpecies();
+        } else if (StringUtils.hasText(this.germplasm.getSubtaxa())) {
+            return this.germplasm.getGenus() + " " + this.germplasm.getSpecies() + " " + this.germplasm.getSubtaxa();
+        } else if (StringUtils.hasText(this.germplasm.getSpecies())) {
+            return this.germplasm.getGenus() + " " + this.germplasm.getSpecies();
+        } else {
+            return this.germplasm.getGenus();
+        }
+    }
+
+    public String getTaxonAuthor() {
+        if (StringUtils.hasText(this.germplasm.getGenusSpeciesSubtaxa())) {
+            return this.germplasm.getSubtaxaAuthority();
+        } else if (StringUtils.hasText(this.germplasm.getGenusSpecies())) {
+            return this.germplasm.getSpeciesAuthority();
+        } else if (StringUtils.hasText(this.germplasm.getSubtaxa())) {
+            return this.germplasm.getSubtaxaAuthority();
+        } else if (StringUtils.hasText(this.germplasm.getSpecies())) {
+            return this.germplasm.getSpeciesAuthority();
+        } else {
+            return null;
+        }
+    }
+
+    public boolean isCollecting() {
+        return this.isCollectingSitePresent()
+            || this.isCollectorInstitutePresent()
+            || this.isCollectorIntituteFieldPresent();
+    }
+
+    private boolean isCollectingSitePresent() {
+        return this.germplasm.getCollectingSite() != null && StringUtils.hasText(this.germplasm.getCollectingSite().getSiteName());
+    }
+
+    private boolean isCollectorInstitutePresent() {
+        return this.germplasm.getCollector() != null &&
+            this.germplasm.getCollector().getInstitute() != null &&
+            StringUtils.hasText(this.germplasm.getCollector().getInstitute().getInstituteName());
+    }
+
+    private boolean isCollectorIntituteFieldPresent() {
+        GermplasmInstituteVO collector = this.germplasm.getCollector();
+        return (collector != null) &&
+            (StringUtils.hasText(collector.getAccessionNumber())
+                || collector.getAccessionCreationDate() != null
+                || StringUtils.hasText(collector.getMaterialType())
+                || StringUtils.hasText(collector.getCollectors())
+                || collector.getRegistrationYear() != null
+                || collector.getDeregistrationYear() != null
+                || StringUtils.hasText(collector.getDistributionStatus())
+            );
+    }
+
+    public boolean isBreeding() {
+        GermplasmInstituteVO breeder = this.germplasm.getBreeder();
+        return breeder != null &&
+            ((breeder.getInstitute() != null && StringUtils.hasText(breeder.getInstitute().getInstituteName())) ||
+                breeder.getAccessionCreationDate() != null ||
+                StringUtils.hasText(breeder.getAccessionNumber()) ||
+                breeder.getRegistrationYear() != null ||
+                breeder.getDeregistrationYear() != null);
+    }
+
+    public boolean isGenealogyPresent() {
+        return isPedigreePresent() || isProgenyPresent();
+    }
+
+    private boolean isProgenyPresent() {
+        return germplasm.getChildren() != null && !germplasm.getChildren().isEmpty();
+    }
+
+    private boolean isPedigreePresent() {
+        return this.pedigree != null &&
+            (StringUtils.hasText(this.pedigree.getParent1Name())
+            || StringUtils.hasText(this.pedigree.getParent2Name())
+            || StringUtils.hasText(this.pedigree.getCrossingPlan())
+            || StringUtils.hasText(this.pedigree.getCrossingYear())
+            || StringUtils.hasText(this.pedigree.getFamilyCode()));
+    }
+
+    public List<MapLocation> getMapLocations() {
+        List<SiteVO> sites = new ArrayList<>();
+        if (germplasm.getCollectingSite() != null) {
+            sites.add(germplasm.getCollectingSite());
+        }
+        if (germplasm.getOriginSite() != null) {
+            sites.add(germplasm.getOriginSite());
+        }
+        if (germplasm.getEvaluationSites() != null) {
+            sites.addAll(germplasm.getEvaluationSites());
+        }
+
+        return MapLocation.sitesToDisplayableMapLocations(sites);
+    }
+
+    public boolean isPuiDisplayedAsLink() {
+        String pui = this.germplasm.getGermplasmPUI();
+        return pui != null && (pui.startsWith("https://doi.org") || pui.startsWith("http://doi.org"));
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/site/MapLocation.java b/backend/src/main/java/fr/inra/urgi/faidare/web/site/MapLocation.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b096853cfff4a467d7a277f9fb4b41e65b2ad01
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/site/MapLocation.java
@@ -0,0 +1,82 @@
+package fr.inra.urgi.faidare.web.site;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.SiteVO;
+import fr.inra.urgi.faidare.utils.Sites;
+
+/**
+ * An object that can be serialized to JSON to serve as a map marker.
+ * @author JB Nizet
+ */
+public final class MapLocation {
+    private final String locationDbId;
+    private final String locationType;
+    private final String locationName;
+    private final double latitude;
+    private final double longitude;
+
+    public MapLocation(String locationDbId,
+                       String locationType,
+                       String locationName,
+                       double latitude,
+                       double longitude) {
+        this.locationDbId = locationDbId;
+        this.locationType = locationType;
+        this.locationName = locationName;
+        this.latitude = latitude;
+        this.longitude = longitude;
+    }
+
+    public MapLocation(LocationVO site) {
+        this(site.getLocationDbId(),
+             site.getLocationType(),
+             site.getLocationName(),
+             site.getLatitude(),
+             site.getLongitude());
+    }
+
+    public MapLocation(SiteVO site) {
+        this(Sites.siteIdToLocationId(site.getSiteId()),
+             site.getSiteType(),
+             site.getSiteName(),
+             site.getLatitude(),
+             site.getLongitude());
+    }
+
+    public static List<MapLocation> locationsToDisplayableMapLocations(List<LocationVO> locations) {
+        return locations.stream()
+                        .filter(location -> location.getLatitude() != null && location.getLongitude() != null)
+                        .map(MapLocation::new)
+                        .collect(Collectors.toList());
+    }
+
+    public static List<MapLocation> sitesToDisplayableMapLocations(List<SiteVO> sites) {
+        return sites.stream()
+                    .filter(site -> site.getLatitude() != null && site.getLongitude() != null)
+                    .map(MapLocation::new)
+                    .collect(Collectors.toList());
+    }
+
+    public String getLocationDbId() {
+        return locationDbId;
+    }
+
+    public String getLocationType() {
+        return locationType;
+    }
+
+    public String getLocationName() {
+        return locationName;
+    }
+
+    public double getLatitude() {
+        return latitude;
+    }
+
+    public double getLongitude() {
+        return longitude;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/site/SiteController.java b/backend/src/main/java/fr/inra/urgi/faidare/web/site/SiteController.java
new file mode 100644
index 0000000000000000000000000000000000000000..645b8fbf84d678e49f1586d32fcc389fba0f5ba3
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/site/SiteController.java
@@ -0,0 +1,85 @@
+package fr.inra.urgi.faidare.web.site;
+
+import java.util.Iterator;
+import java.util.List;
+
+import fr.inra.urgi.faidare.api.NotFoundException;
+import fr.inra.urgi.faidare.config.FaidareProperties;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentSearchCriteria;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.repository.es.LocationRepository;
+import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
+import fr.inra.urgi.faidare.utils.Sitemaps;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
+
+/**
+ * Controller used to display a site card based on its ID.
+ * @author JB Nizet
+ */
+@Controller("webSiteController")
+@RequestMapping("/sites")
+public class SiteController {
+
+    private final LocationRepository locationRepository;
+    private final FaidareProperties faidareProperties;
+    private final XRefDocumentRepository xRefDocumentRepository;
+
+    public SiteController(LocationRepository locationRepository,
+                          FaidareProperties faidareProperties,
+                          XRefDocumentRepository xRefDocumentRepository) {
+        this.locationRepository = locationRepository;
+        this.faidareProperties = faidareProperties;
+        this.xRefDocumentRepository = xRefDocumentRepository;
+    }
+
+    @GetMapping("/{siteId}")
+    public ModelAndView get(@PathVariable("siteId") String siteId) {
+        LocationVO site = locationRepository.getById(siteId);
+
+        if (site == null) {
+            throw new NotFoundException("Site with ID " + siteId + " not found");
+        }
+
+        List<XRefDocumentVO> crossReferences = xRefDocumentRepository.find(
+             XRefDocumentSearchCriteria.forXRefId(site.getLocationDbId())
+        );
+
+        return new ModelAndView("site",
+                                "model",
+                                new SiteModel(
+                                    site,
+                                    faidareProperties.getByUri(site.getSourceUri()),
+                                    crossReferences
+                                )
+        );
+    }
+
+    @GetMapping(value = "/sitemap-{index}.txt")
+    @ResponseBody
+    public ResponseEntity<StreamingResponseBody> sitemap(@PathVariable("index") int index) {
+        if (index < 0 || index >= Sitemaps.BUCKET_COUNT) {
+            throw new NotFoundException("no sitemap for this index");
+        }
+        StreamingResponseBody body = out -> {
+            Iterator<LocationSitemapVO> iterator = locationRepository.scrollAllForSitemap(1000);
+            Sitemaps.generateSitemap(
+                "/sites/sitemap-" + index + ".txt",
+                out,
+                iterator,
+                vo -> Math.floorMod(vo.getLocationDbId().hashCode(), Sitemaps.BUCKET_COUNT) == index,
+                vo -> "/sites/" + vo.getLocationDbId()
+            );
+        };
+        return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(body);
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/site/SiteModel.java b/backend/src/main/java/fr/inra/urgi/faidare/web/site/SiteModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd8f7bb80bbb6cad8d29a9c76c3b6e1a39dce06f
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/site/SiteModel.java
@@ -0,0 +1,118 @@
+package fr.inra.urgi.faidare.web.site;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+
+/**
+ * The model used by the site page
+ * @author JB Nizet
+ */
+public final class SiteModel {
+    private static final Set<String> IGNORED_PROPERTIES =
+        new HashSet<>(Arrays.asList("Site status",
+                                    "Coordinates precision",
+                                    "Slope",
+                                    "Exposure",
+                                    "Geographical location",
+                                    "Distance to city",
+                                    "Direction from city",
+                                    "Environment type",
+                                    "Topography",
+                                    "Comment"));
+
+    private final LocationVO site;
+    private final DataSource source;
+    private final Map<String, Object> additionalInfo;
+    private final List<XRefDocumentVO> crossReferences;
+    private final List<Map.Entry<String, Object>> additionalInfoProperties;
+
+    public SiteModel(LocationVO site,
+                     DataSource source,
+                     List<XRefDocumentVO> crossReferences) {
+        this.site = site;
+        this.source = source;
+        this.additionalInfo = site.getAdditionalInfo() == null ? Collections.emptyMap() : site.getAdditionalInfo().getProperties();
+        this.crossReferences = crossReferences;
+        this.additionalInfoProperties =
+            this.additionalInfo
+                .entrySet()
+                .stream()
+                .filter(entry -> !IGNORED_PROPERTIES.contains(entry.getKey()))
+                .filter(entry -> entry.getValue() != null && !entry.getValue().toString().isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .collect(Collectors.toList());
+    }
+
+    public LocationVO getSite() {
+        return site;
+    }
+
+    public DataSource getSource() {
+        return source;
+    }
+
+    public Map<String, Object> getAdditionalInfo() {
+        return this.additionalInfo;
+    }
+
+    public Object getSiteStatus() {
+        return this.additionalInfo.get("Site status");
+    }
+
+    public Object getCoordinatesPrecision() {
+        return this.additionalInfo.get("Coordinates precision");
+    }
+
+    public Object getGeographicalLocation() {
+        return this.additionalInfo.get("Geographical location");
+    }
+
+    public Object getSlope() {
+        return this.additionalInfo.get("Slope");
+    }
+
+    public Object getExposure() {
+        return this.additionalInfo.get("Exposure");
+    }
+
+    public Object getTopography() {
+        return this.additionalInfo.get("Topography");
+    }
+
+    public Object getEnvironmentType() {
+        return this.additionalInfo.get("Environment type");
+    }
+
+    public Object getDistanceToCity() {
+        return this.additionalInfo.get("Distance to city");
+    }
+
+    public Object getDirectionFromCity() {
+        return this.additionalInfo.get("Direction from city");
+    }
+
+    public Object getComment() {
+        return this.additionalInfo.get("Comment");
+    }
+
+    public List<Map.Entry<String, Object>> getAdditionalInfoProperties() {
+        return additionalInfoProperties;
+    }
+
+    public List<XRefDocumentVO> getCrossReferences() {
+        return crossReferences;
+    }
+
+    public List<MapLocation> getMapLocations() {
+        return MapLocation.locationsToDisplayableMapLocations(Collections.singletonList(this.site));
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/sitemap/SitemapIndexController.java b/backend/src/main/java/fr/inra/urgi/faidare/web/sitemap/SitemapIndexController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f80d9e364075a59323f97273847fcd89e5b9df29
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/sitemap/SitemapIndexController.java
@@ -0,0 +1,59 @@
+package fr.inra.urgi.faidare.web.sitemap;
+
+import java.nio.charset.StandardCharsets;
+
+import fr.inra.urgi.faidare.utils.Sitemaps;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Controller used to generate the sitemap index containing links to the site sitemap
+ * (unique), the N sitemaps for the studies and the N sitemaps for the germplasms.
+ *
+ * Sitemaps for studies and germplasms are split in N buckets because sitemaps
+ * can't be more than 50 MB and can't have more than 50,000 entries.
+ * Splitting them in N sitemaps makes it almost sure that none of the sitemaps
+ * overflows those limits.
+ *
+ * The sitemaps are split based on the hashCode of the ID of the document:
+ * if a document's hash code modulo N is 0, then it's in the sitemap-0.txt, etc.
+ *
+ * @author JB Nizet
+ */
+@RestController
+@RequestMapping("")
+public class SitemapIndexController {
+    @GetMapping("/sitemap.xml")
+    public ResponseEntity<byte[]> sitemapIndex() {
+        StringBuilder builder = new StringBuilder();
+        builder
+            .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+            .append("<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n");
+
+        for (int i = 0; i < Sitemaps.BUCKET_COUNT; i++) {
+            appendSiteMap(builder, "/sites/sitemap-" + i + ".txt");
+        }
+        for (int i = 0; i < Sitemaps.BUCKET_COUNT; i++) {
+            appendSiteMap(builder, "/germplasms/sitemap-" + i + ".txt");
+        }
+        for (int i = 0; i < Sitemaps.BUCKET_COUNT; i++) {
+            appendSiteMap(builder, "/studies/sitemap-" + i + ".txt");
+        }
+        builder.append("</sitemapindex>");
+
+        return ResponseEntity.ok()
+                             .contentType(MediaType.TEXT_XML)
+                             .body(builder.toString().getBytes(StandardCharsets.UTF_8));
+    }
+
+    public void appendSiteMap(StringBuilder builder, String path) {
+        builder.append("  <sitemap>\n")
+               .append("    <loc>")
+               .append(Sitemaps.generateSitemapUrl(path))
+               .append("</loc>\n")
+               .append("  </sitemap>\n");
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/study/StudyController.java b/backend/src/main/java/fr/inra/urgi/faidare/web/study/StudyController.java
new file mode 100644
index 0000000000000000000000000000000000000000..989b9a498d271c071e041c46bb3a34f01ac650d0
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/study/StudyController.java
@@ -0,0 +1,231 @@
+package fr.inra.urgi.faidare.web.study;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import com.google.common.collect.Lists;
+import fr.inra.urgi.faidare.api.NotFoundException;
+import fr.inra.urgi.faidare.config.FaidareProperties;
+import fr.inra.urgi.faidare.domain.criteria.GermplasmPOSTSearchCriteria;
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.TrialVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
+import fr.inra.urgi.faidare.domain.data.study.StudySitemapVO;
+import fr.inra.urgi.faidare.domain.data.variable.ObservationVariableVO;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentSearchCriteria;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.repository.es.GermplasmRepository;
+import fr.inra.urgi.faidare.repository.es.LocationRepository;
+import fr.inra.urgi.faidare.repository.es.StudyRepository;
+import fr.inra.urgi.faidare.repository.es.TrialRepository;
+import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
+import fr.inra.urgi.faidare.repository.file.CropOntologyRepository;
+import fr.inra.urgi.faidare.utils.Sitemaps;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
+
+/**
+ * Controller used to display a study card based on its ID.
+ * @author JB Nizet
+ */
+@Controller("webStudyController")
+@RequestMapping("/studies")
+public class StudyController {
+
+    private final StudyRepository studyRepository;
+    private final FaidareProperties faidareProperties;
+    private final XRefDocumentRepository xRefDocumentRepository;
+    private final GermplasmRepository germplasmRepository;
+    private final CropOntologyRepository cropOntologyRepository;
+    private final TrialRepository trialRepository;
+    private final LocationRepository locationRepository;
+
+    public StudyController(StudyRepository studyRepository,
+                           FaidareProperties faidareProperties,
+                           XRefDocumentRepository xRefDocumentRepository,
+                           GermplasmRepository germplasmRepository,
+                           CropOntologyRepository cropOntologyRepository,
+                           TrialRepository trialRepository,
+                           LocationRepository locationRepository) {
+        this.studyRepository = studyRepository;
+        this.faidareProperties = faidareProperties;
+        this.xRefDocumentRepository = xRefDocumentRepository;
+        this.germplasmRepository = germplasmRepository;
+        this.cropOntologyRepository = cropOntologyRepository;
+        this.trialRepository = trialRepository;
+        this.locationRepository = locationRepository;
+    }
+
+    @GetMapping("/{studyId}")
+    public ModelAndView get(@PathVariable("studyId") String studyId, Locale locale) {
+        StudyDetailVO study = studyRepository.getById(studyId);
+
+        if (study == null) {
+            throw new NotFoundException("Study with ID " + studyId + " not found");
+        }
+
+        List<XRefDocumentVO> crossReferences = xRefDocumentRepository.find(
+            XRefDocumentSearchCriteria.forXRefId(study.getStudyDbId())
+        );
+
+        List<GermplasmVO> germplasms = getGermplasms(study);
+        List<ObservationVariableVO> variables = getVariables(study, locale);
+        List<TrialVO> trials = getTrials(study);
+        LocationVO location = getLocation(study);
+
+        return new ModelAndView("study",
+                                "model",
+                                new StudyModel(
+                                    study,
+                                    faidareProperties.getByUri(study.getSourceUri()),
+                                    germplasms,
+                                    variables,
+                                    trials,
+                                    crossReferences,
+                                    location
+                                )
+        );
+    }
+
+    @GetMapping(value = "/sitemap-{index}.txt")
+    @ResponseBody
+    public ResponseEntity<StreamingResponseBody> sitemap(@PathVariable("index") int index) {
+        if (index < 0 || index >= Sitemaps.BUCKET_COUNT) {
+            throw new NotFoundException("no sitemap for this index");
+        }
+        StreamingResponseBody body = out -> {
+            Iterator<StudySitemapVO> iterator = studyRepository.scrollAllForSitemap(1000);
+            Sitemaps.generateSitemap(
+                "/sudies/sitemap-" + index + ".txt",
+                out,
+                iterator,
+                vo -> Math.floorMod(vo.getStudyDbId().hashCode(), Sitemaps.BUCKET_COUNT) == index,
+                vo -> "/studies/" + vo.getStudyDbId());
+        };
+        return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(body);
+    }
+
+    private LocationVO getLocation(StudyDetailVO study) {
+        if (Strings.isBlank(study.getLocationDbId())) {
+            return null;
+        }
+        return locationRepository.getById(study.getLocationDbId());
+    }
+
+    private List<GermplasmVO> getGermplasms(StudyDetailVO study) {
+        if (study.getGermplasmDbIds() == null || study.getGermplasmDbIds().isEmpty()) {
+            return Collections.emptyList();
+        } else {
+            GermplasmPOSTSearchCriteria germplasmCriteria = new GermplasmPOSTSearchCriteria();
+            germplasmCriteria.setGermplasmDbIds(Lists.newArrayList(study.getGermplasmDbIds()));
+            return germplasmRepository.find(germplasmCriteria)
+                .stream()
+                .sorted(Comparator.comparing(GermplasmVO::getGermplasmName))
+                .collect(Collectors.toList());
+        }
+    }
+
+    private List<ObservationVariableVO> getVariables(StudyDetailVO study, Locale locale) {
+        Set<String> variableIds = studyRepository.getVariableIds(study.getStudyDbId());
+        List<ObservationVariableVO> variables = cropOntologyRepository.getVariableByIds(variableIds);
+        return filterVariablesForLocale(variables, locale)
+            .sorted(Comparator.comparing(ObservationVariableVO::getObservationVariableDbId))
+            .collect(Collectors.toList());
+    }
+
+    /**
+     * Filter the variables by language. The principles are the following. First, the languages of the variables
+     * are normalized (to transform FRA into fr for example).
+     * Then, several cases are possible.
+     *
+     * If there is no variable with the requested language, then we find the reference language.
+     * The reference language is en if there is at least one variable with that language.
+     * The reference is the first non null language found if there is no variable with the en language.
+     * Then, we keep all the variables with the reference language (if any), and all the variables without language.
+     *
+     * If there is at least one variable with the requested language, then we keep all the variables
+     * with the requested language, and all the variables without language.
+     */
+    private Stream<ObservationVariableVO> filterVariablesForLocale(List<ObservationVariableVO> variables, Locale locale) {
+        if (variables.isEmpty()) {
+            return variables.stream();
+        }
+
+        String requestedLanguage = locale.getLanguage();
+        String referenceLanguage = findReferenceLanguage(requestedLanguage, variables);
+
+        return variables.stream()
+                        .filter(variable ->
+                                    referenceLanguage == null
+                                        || !StringUtils.hasText(variable.getLanguage())
+                                        || normalizeLanguage(variable.getLanguage()).equals(referenceLanguage));
+    }
+
+    private String findReferenceLanguage(String requestedLanguage, List<ObservationVariableVO> variables) {
+        Set<String> normalizedVariableLanguages =
+            variables.stream()
+                     .map(ObservationVariableVO::getLanguage)
+                     .filter(StringUtils::hasText)
+                     .map(this::normalizeLanguage)
+                     .collect(Collectors.toSet());
+
+        String referenceLanguage = null;
+        if (normalizedVariableLanguages.contains(requestedLanguage)) {
+            referenceLanguage = requestedLanguage;
+        } else if (normalizedVariableLanguages.contains("en")) {
+            referenceLanguage = "en";
+        } else if (!normalizedVariableLanguages.isEmpty()) {
+            referenceLanguage = normalizedVariableLanguages.iterator().next();
+        }
+        return referenceLanguage;
+    }
+
+    private String normalizeLanguage(String language) {
+        // this is a hack trying to accomodate for languages not bein standard in the data
+        String languageInLowerCase = language.toLowerCase();
+        if (languageInLowerCase.length() == 3) {
+            switch (languageInLowerCase) {
+                case "fra":
+                    return "fr";
+                case "esp":
+                case "spa":
+                    return "es";
+                case "eng":
+                    return "en";
+            }
+        }
+        return languageInLowerCase;
+    }
+
+    private List<TrialVO> getTrials(StudyDetailVO study) {
+        if (study.getTrialDbIds() == null || study.getTrialDbIds().isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        return study.getTrialDbIds()
+                    .stream()
+                    .sorted(Comparator.naturalOrder())
+                    .map(trialRepository::getById)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toList());
+    }
+
+
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/study/StudyModel.java b/backend/src/main/java/fr/inra/urgi/faidare/web/study/StudyModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc77dfc3d9b9fdb7da63dd7b47afb15ab1e3bff6
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/study/StudyModel.java
@@ -0,0 +1,90 @@
+package fr.inra.urgi.faidare.web.study;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.TrialVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
+import fr.inra.urgi.faidare.domain.data.variable.ObservationVariableVO;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.web.site.MapLocation;
+
+/**
+ * The model used by the study page
+ * @author JB Nizet
+ */
+public final class StudyModel {
+    private final StudyDetailVO study;
+    private final DataSource source;
+    private final List<GermplasmVO> germplasms;
+    private final List<ObservationVariableVO> variables;
+    private final List<TrialVO> trials;
+    private final List<XRefDocumentVO> crossReferences;
+    private final LocationVO location;
+    private final List<Map.Entry<String, Object>> additionalInfoProperties;
+
+    public StudyModel(StudyDetailVO study,
+                      DataSource source,
+                      List<GermplasmVO> germplasms,
+                      List<ObservationVariableVO> variables,
+                      List<TrialVO> trials,
+                      List<XRefDocumentVO> crossReferences,
+                      LocationVO location) {
+        this.study = study;
+        this.source = source;
+        this.germplasms = germplasms;
+        this.variables = variables;
+        this.trials = trials;
+        this.crossReferences = crossReferences;
+        this.location = location;
+
+        Map<String, Object> additionalInfo =
+            study.getAdditionalInfo() == null ? Collections.emptyMap() : study.getAdditionalInfo().getProperties();
+        this.additionalInfoProperties =
+            additionalInfo.entrySet()
+                          .stream()
+                          .filter(entry -> entry.getValue() != null && !entry.getValue().toString().isEmpty())
+                          .sorted(Map.Entry.comparingByKey())
+                          .collect(Collectors.toList());
+    }
+
+    public StudyDetailVO getStudy() {
+        return study;
+    }
+
+    public DataSource getSource() {
+        return source;
+    }
+
+    public List<XRefDocumentVO> getCrossReferences() {
+        return crossReferences;
+    }
+
+    public List<GermplasmVO> getGermplasms() {
+        return germplasms;
+    }
+
+    public List<ObservationVariableVO> getVariables() {
+        return variables;
+    }
+
+    public List<TrialVO> getTrials() {
+        return trials;
+    }
+
+    public List<Map.Entry<String, Object>> getAdditionalInfoProperties() {
+        return additionalInfoProperties;
+    }
+
+    public List<MapLocation> getMapLocations() {
+        if (this.location == null) {
+            return Collections.emptyList();
+        }
+        return MapLocation.locationsToDisplayableMapLocations(Collections.singletonList(this.location));
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/Coordinates.java b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/Coordinates.java
new file mode 100644
index 0000000000000000000000000000000000000000..554929b11d88e103093f808be0ba969118c47772
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/Coordinates.java
@@ -0,0 +1,71 @@
+package fr.inra.urgi.faidare.web.thymeleaf;
+
+import java.text.DecimalFormat;
+import java.util.Locale;
+
+/**
+ * The actual object offering Coordinates helper methods to thymeleaf
+ * @author JB Nizet
+ */
+public class Coordinates {
+    private final Locale locale;
+
+    public Coordinates(Locale locale) {
+        this.locale = locale;
+    }
+
+    public String format(Double value) {
+        if (value == null) {
+            return "";
+        }
+        return DecimalFormat.getInstance(locale).format(value);
+    }
+
+    public String formatLatitude(Double value) {
+        if (value == null) {
+            return "";
+        }
+        return this.format(value) + " — " + this.toLatitudeDegrees(value);
+    }
+
+    public String formatLongitude(Double value) {
+        if (value == null) {
+            return "";
+        }
+        return this.format(value) + " — " + this.toLongitudeDegrees(value);
+    }
+
+    public String toLatitudeDegrees(Double latitude) {
+        if (latitude == null) {
+            return "";
+        }
+
+        return toDegrees(latitude) + " " + ((latitude < 0) ? "S" : "N");
+    }
+
+    public String toLongitudeDegrees(Double longitude) {
+        if (longitude == null) {
+            return "";
+        }
+
+        return toDegrees(longitude) + " " + ((longitude < 0) ? "W" : "E");
+    }
+
+    private String toDegrees(double value) {
+        double absoluteDegrees = Math.abs(value);
+        int fullDegrees = (int) absoluteDegrees;
+        double remainingMinutes = (absoluteDegrees - fullDegrees) * 60;
+        int minutes = (int) remainingMinutes;
+        double remainingSeconds = (remainingMinutes - minutes) * 60;
+        int seconds = (int) remainingSeconds;
+        if (seconds == 60) {
+            minutes += 1;
+            seconds = 0;
+        }
+        if (minutes == 60) {
+            fullDegrees += 1;
+            minutes = 0;
+        }
+        return fullDegrees + "°" + minutes + "'" + seconds;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/CoordinatesDialect.java b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/CoordinatesDialect.java
new file mode 100644
index 0000000000000000000000000000000000000000..d443e589ca1c8e82c00960faeb9f15733db0e102
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/CoordinatesDialect.java
@@ -0,0 +1,28 @@
+package fr.inra.urgi.faidare.web.thymeleaf;
+
+import org.springframework.stereotype.Component;
+import org.thymeleaf.dialect.AbstractDialect;
+import org.thymeleaf.dialect.IDialect;
+import org.thymeleaf.dialect.IExpressionObjectDialect;
+import org.thymeleaf.expression.IExpressionObjectFactory;
+import org.thymeleaf.extras.java8time.dialect.Java8TimeExpressionFactory;
+
+/**
+ * A thymeleaf dialect allowing to transform coordinates (latitude and longitude)
+ * to degrees.
+ * @author JB Nizet
+ */
+@Component
+public class CoordinatesDialect extends AbstractDialect implements IExpressionObjectDialect {
+
+    private final IExpressionObjectFactory COORDINATES_EXPRESSION_OBJECTS_FACTORY = new CoordinatesExpressionFactory();
+
+    protected CoordinatesDialect() {
+        super("coordinates");
+    }
+
+    @Override
+    public IExpressionObjectFactory getExpressionObjectFactory() {
+        return COORDINATES_EXPRESSION_OBJECTS_FACTORY;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/CoordinatesExpressionFactory.java b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/CoordinatesExpressionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3c25cc8577aae0cac73a894915d6c33edd6d8ca
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/CoordinatesExpressionFactory.java
@@ -0,0 +1,36 @@
+package fr.inra.urgi.faidare.web.thymeleaf;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.thymeleaf.context.IExpressionContext;
+import org.thymeleaf.expression.IExpressionObjectFactory;
+import org.thymeleaf.extras.java8time.expression.Temporals;
+
+/**
+ * The object factory for the {@link CoordinatesDialect}
+ * @author JB Nizet
+ */
+public class CoordinatesExpressionFactory implements IExpressionObjectFactory {
+    private static final String COORDINATES_EVALUATION_VARIABLE_NAME = "coordinates";
+
+    private static final Set<String> ALL_EXPRESSION_OBJECT_NAMES =
+        Collections.singleton(COORDINATES_EVALUATION_VARIABLE_NAME);
+
+    @Override
+    public Set<String> getAllExpressionObjectNames() {
+        return ALL_EXPRESSION_OBJECT_NAMES;
+    }
+
+    @Override
+    public Object buildObject(IExpressionContext context, String expressionObjectName) {
+        return new Coordinates(context.getLocale());
+    }
+
+    @Override
+    public boolean isCacheable(String expressionObjectName) {
+        return true;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareDialect.java b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareDialect.java
new file mode 100644
index 0000000000000000000000000000000000000000..26bfc5611683c9a854efbe84084a2164827c57f6
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareDialect.java
@@ -0,0 +1,27 @@
+package fr.inra.urgi.faidare.web.thymeleaf;
+
+import fr.inra.urgi.faidare.config.FaidareProperties;
+import org.springframework.stereotype.Component;
+import org.thymeleaf.dialect.AbstractDialect;
+import org.thymeleaf.dialect.IExpressionObjectDialect;
+import org.thymeleaf.expression.IExpressionObjectFactory;
+
+/**
+ * A thymeleaf dialect allowing to perform various tasks in the template related to Faidare
+ * @author JB Nizet
+ */
+@Component
+public class FaidareDialect extends AbstractDialect implements IExpressionObjectDialect {
+
+    private final IExpressionObjectFactory faidareExpressionFactory;
+
+    public FaidareDialect(FaidareProperties faidareProperties) {
+        super("faidare");
+        faidareExpressionFactory = new FaidareExpressionFactory(faidareProperties.getSearchUrl());
+    }
+
+    @Override
+    public IExpressionObjectFactory getExpressionObjectFactory() {
+        return faidareExpressionFactory;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareExpressionFactory.java b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareExpressionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ccd5fe9aadb56f9799d230e153b37c3525d37bd
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareExpressionFactory.java
@@ -0,0 +1,39 @@
+package fr.inra.urgi.faidare.web.thymeleaf;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.thymeleaf.context.IExpressionContext;
+import org.thymeleaf.expression.IExpressionObjectFactory;
+
+/**
+ * The object factory for the {@link FaidareDialect}
+ * @author JB Nizet
+ */
+public class FaidareExpressionFactory implements IExpressionObjectFactory {
+    private static final String FAIDARE_EVALUATION_VARIABLE_NAME = "faidare";
+
+    private static final Set<String> ALL_EXPRESSION_OBJECT_NAMES =
+        Collections.singleton(FAIDARE_EVALUATION_VARIABLE_NAME);
+
+    private final String searchUrl;
+
+    public FaidareExpressionFactory(String searchUrl) {
+        this.searchUrl = searchUrl;
+    }
+
+    @Override
+    public Set<String> getAllExpressionObjectNames() {
+        return ALL_EXPRESSION_OBJECT_NAMES;
+    }
+
+    @Override
+    public Object buildObject(IExpressionContext context, String expressionObjectName) {
+        return new FaidareExpressions(context.getLocale(), searchUrl);
+    }
+
+    @Override
+    public boolean isCacheable(String expressionObjectName) {
+        return true;
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareExpressions.java b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareExpressions.java
new file mode 100644
index 0000000000000000000000000000000000000000..a88283830f9c0fb1408a3b59423bd74456933db8
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/FaidareExpressions.java
@@ -0,0 +1,100 @@
+package fr.inra.urgi.faidare.web.thymeleaf;
+
+import java.nio.charset.StandardCharsets;
+import java.text.DecimalFormat;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.function.Function;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import fr.inra.urgi.faidare.domain.data.germplasm.CollPopVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.TaxonSourceVO;
+import fr.inra.urgi.faidare.utils.Sites;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * The actual object offering Faidare helper methods to thymeleaf
+ * @author JB Nizet
+ */
+public class FaidareExpressions {
+
+    private static final Map<String, Function<String, String>> TAXON_ID_URL_FACTORIES_BY_SOURCE_NAME =
+        createTaxonIdUrlFactories();
+
+    private static final List<NavbarEntry> NAVBAR_ENTRIES =
+        createNavbarEntries();
+
+    private static Map<String, Function<String, String>> createTaxonIdUrlFactories() {
+        Map<String, Function<String, String>> result = new HashMap<>();
+        result.put("NCBI", s -> "https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=" + s);
+        result.put("ThePlantList", s -> "http://www.theplantlist.org/tpl1.1/record/" + s);
+        result.put("TAXREF", s -> "https://inpn.mnhn.fr/espece/cd_nom/" + s);
+        result.put("CatalogueOfLife", s -> "http://www.catalogueoflife.org/col/details/species/id/" + s);
+        return Collections.unmodifiableMap(result);
+    }
+
+    private static List<NavbarEntry> createNavbarEntries() {
+        return Arrays.asList(
+            NavbarEntry.menu("URGI", Arrays.asList(
+                NavbarEntry.link("Home", "https://urgi.versailles.inrae.fr"),
+                NavbarEntry.link("News", "https://urgi.versailles.inrae.fr/About-us/News"),
+                NavbarEntry.link("About us", "https://urgi.versailles.inrae.fr/About-us")
+            )),
+            NavbarEntry.menu("More...", Arrays.asList(
+                NavbarEntry.link("About", "https://urgi.versailles.inrae.fr/faidare/about"),
+                NavbarEntry.link("Join us", "https://urgi.versailles.inrae.fr/faidare/join"),
+                NavbarEntry.link("Terms of use", "https://urgi.versailles.inrae.fr/faidare/legal"),
+                NavbarEntry.link("Help", "https://urgi.versailles.inrae.fr/faidare/help"),
+                NavbarEntry.link("News/Perspectives", "https://urgi.versailles.inrae.fr/faidare/news")
+            ))
+        );
+    }
+
+    private final Locale locale;
+    private final String searchUrl;
+
+    public FaidareExpressions(Locale locale, String searchUrl) {
+        this.locale = locale;
+        this.searchUrl = searchUrl;
+    }
+
+    public String toSiteParam(String siteId) {
+        return Sites.siteIdToLocationId(siteId);
+    }
+
+    public String collPopTitle(CollPopVO collPopVO) {
+        return collPopTitle(collPopVO, Function.identity());
+    }
+
+    public String collPopTitleWithoutUnderscores(CollPopVO collPopVO) {
+        return collPopTitle(collPopVO, s -> s.replace('_', ' '));
+    }
+
+    public String taxonIdUrl(TaxonSourceVO taxonSource) {
+        Function<String, String> urlFactory =
+            TAXON_ID_URL_FACTORIES_BY_SOURCE_NAME.get(taxonSource.getSourceName());
+        return urlFactory != null ? urlFactory.apply(taxonSource.getTaxonId()) : null;
+    }
+
+    public List<NavbarEntry> navbarEntries() {
+        return NAVBAR_ENTRIES;
+    }
+
+    public String searchUrl() {
+        return searchUrl;
+    }
+
+    private String collPopTitle(CollPopVO collPopVO, Function<String, String> nameTransformer) {
+        if (Strings.isBlank(collPopVO.getType())) {
+            return nameTransformer.apply(collPopVO.getName());
+        } else {
+            return nameTransformer.apply(collPopVO.getName()) + " (" + collPopVO.getType() + ")";
+        }
+    }
+}
diff --git a/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/NavbarEntry.java b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/NavbarEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..8925aec060762927cf87328c2e40164e5bb7e589
--- /dev/null
+++ b/backend/src/main/java/fr/inra/urgi/faidare/web/thymeleaf/NavbarEntry.java
@@ -0,0 +1,40 @@
+package fr.inra.urgi.faidare.web.thymeleaf;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A navbar link
+ * @author JB Nizet
+ */
+public final class NavbarEntry {
+    private final String label;
+    private final String url;
+    private final List<NavbarEntry> subMenu;
+
+    private NavbarEntry(String label, String url, List<NavbarEntry> subMenu) {
+        this.label = label;
+        this.url = url;
+        this.subMenu = subMenu;
+    }
+
+    public static NavbarEntry link(String label, String url) {
+        return new NavbarEntry(label, url, Collections.emptyList());
+    }
+
+    public static NavbarEntry menu(String label, List<NavbarEntry> subMenu) {
+        return new NavbarEntry(label, null, subMenu);
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public List<NavbarEntry> getSubMenu() {
+        return subMenu;
+    }
+}
diff --git a/backend/src/main/main.iml b/backend/src/main/main.iml
deleted file mode 100644
index 50f3d6bc79c58fa92df31bb59ab229d1e7c0c12e..0000000000000000000000000000000000000000
--- a/backend/src/main/main.iml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="Gradle: io.swagger:swagger-annotations:1.5.21" level="project" />
-    <orderEntry type="library" name="Gradle: org.springframework:spring-beans:5.1.4.RELEASE" level="project" />
-    <orderEntry type="library" name="Gradle: org.springframework:spring-web:5.1.4.RELEASE" level="project" />
-    <orderEntry type="library" name="Gradle: io.springfox:springfox-core:2.9.2" level="project" />
-    <orderEntry type="library" name="Gradle: io.springfox:springfox-spring-web:2.9.2" level="project" />
-    <orderEntry type="library" name="Gradle: javax.validation:validation-api:2.0.1.Final" level="project" />
-    <orderEntry type="library" name="Gradle: com.google.guava:guava:27.0.1-jre" level="project" />
-    <orderEntry type="library" name="Gradle: commons-collections:commons-collections:3.2.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore:4.4.10" level="project" />
-    <orderEntry type="library" name="Gradle: org.elasticsearch.client:elasticsearch-rest-client:6.4.3" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore-nio:4.4.10" level="project" />
-    <orderEntry type="library" name="Gradle: org.springframework.boot:spring-boot-autoconfigure:2.1.2.RELEASE" level="project" />
-    <orderEntry type="library" name="Gradle: org.springframework:spring-context:5.1.4.RELEASE" level="project" />
-    <orderEntry type="library" name="Gradle: com.fasterxml.jackson.core:jackson-databind:2.9.8" level="project" />
-    <orderEntry type="library" name="Gradle: org.springframework.boot:spring-boot:2.1.2.RELEASE" level="project" />
-    <orderEntry type="library" name="Gradle: org.springframework.security:spring-security-config:5.1.3.RELEASE" level="project" />
-    <orderEntry type="library" name="Gradle: io.springfox:springfox-spi:2.9.2" level="project" />
-    <orderEntry type="library" name="Gradle: io.springfox:springfox-swagger2:2.9.2" level="project" />
-    <orderEntry type="library" name="Gradle: org.elasticsearch:elasticsearch:6.5.4" level="project" />
-    <orderEntry type="library" name="Gradle: org.slf4j:slf4j-api:1.7.25" level="project" />
-    <orderEntry type="library" name="Gradle: org.elasticsearch.client:elasticsearch-rest-high-level-client:6.5.4" level="project" />
-    <orderEntry type="library" name="Gradle: org.elasticsearch:elasticsearch-core:6.5.4" level="project" />
-    <orderEntry type="library" name="Gradle: org.springframework:spring-core:5.1.4.RELEASE" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.tomcat.embed:tomcat-embed-core:9.0.14" level="project" />
-    <orderEntry type="library" name="Gradle: com.opencsv:opencsv:4.4" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.commons:commons-lang3:3.8.1" level="project" />
-    <orderEntry type="library" name="Gradle: org.apache.lucene:lucene-join:7.5.0" level="project" />
-    <orderEntry type="library" name="Gradle: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml
index 26c55fc3839132b3f6aca48b40f00c061a6b180f..9cce0f6a869386f51c7b4fd726c61079791de4ba 100644
--- a/backend/src/main/resources/application.yml
+++ b/backend/src/main/resources/application.yml
@@ -1,3 +1,14 @@
+spring:
+  config:
+    import: 'optional:configserver:'
+  mvc:
+    pathmatch:
+      matching-strategy: ant-path-matcher
+  cloud:
+    config:
+      name: faidare-cards
+      uri: ${SPRING_CONFIG_URI:http://localhost:8888}
+
 data:
   elasticsearch:
     host: 127.0.0.1
@@ -12,19 +23,20 @@ management:
       exposure:
         include: '*'
 
-logging.level:
-  root: ERROR
-  org.springframework:
-    boot.web.embedded.tomcat.TomcatWebServer: INFO
-    web.client.RestTemplate: DEBUG
-  fr.inra: DEBUG
+logging:
+  level:
+    root: ERROR
+    org.springframework:
+      boot.web.embedded.tomcat.TomcatWebServer: INFO
+      web.client.RestTemplate: DEBUG
+    fr.inra: DEBUG
 
 faidare:
   elasticsearch-indexing-template:
     faidare_{documentType}_dev
 
   elasticsearch-xref-index-name:
-    urgi_xref_dev
+    faidare_xref_dev
 
   cropOntology-repository-url:
     https://urgi.versailles.inrae.fr/files/ephesis/trait-ontology/data_16.3/ontology-repository.json
@@ -33,6 +45,8 @@ faidare:
   security-user-group-ws-url:
   security-user-group-ws-token:
 
+  search-url: https://urgi.versailles.inrae.fr/faidare/search
+
   # TODO: Update URIs to match URL (update in generated JSON document too)
   # Warning! URIs should match with FAIDARE datadiscovery 'schema:includedInDataCatalog' field value
   data-sources:
@@ -86,7 +100,26 @@ server:
       - text/html
       - text/css
       - text/markdown
+      - text/plain
   port: 8380
   servlet:
     context-path: /faidare-dev
 
+springdoc:
+  packagesToScan: fr.inra.urgi.faidare.api
+  pathsToMatch: /faidare/**, /brapi/**
+  swagger-ui:
+    operationsSorter: alpha
+    tagsSorter: alpha
+
+---
+spring:
+  config:
+    activate:
+      on-profile:
+        dev
+  web:
+    resources:
+      static-locations:
+        - classpath:/static/
+        - file:./web/build/dist/
diff --git a/backend/src/main/resources/bootstrap.yml b/backend/src/main/resources/bootstrap.yml
deleted file mode 100644
index 3be3a00c606b53b0df359c502f7a0c5d1929f417..0000000000000000000000000000000000000000
--- a/backend/src/main/resources/bootstrap.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-spring:
-  application.name: faidare
-  cloud:
-    config:
-      uri: ${SPRING_CONFIG_URI:http://localhost:8888}
-      # label: feat(_)configure_openstack_ci
diff --git a/frontend/src/assets/faidare/favicon.ico b/backend/src/main/resources/static/resources/images/favicon.ico
similarity index 100%
rename from frontend/src/assets/faidare/favicon.ico
rename to backend/src/main/resources/static/resources/images/favicon.ico
diff --git a/backend/src/main/resources/static/resources/images/logo.png b/backend/src/main/resources/static/resources/images/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..86b3ab108693a19cca5a05c95faebd8573e23389
Binary files /dev/null and b/backend/src/main/resources/static/resources/images/logo.png differ
diff --git a/frontend/src/assets/faidare/images/marker-icon-blue.png b/backend/src/main/resources/static/resources/images/marker-icon-blue.png
similarity index 100%
rename from frontend/src/assets/faidare/images/marker-icon-blue.png
rename to backend/src/main/resources/static/resources/images/marker-icon-blue.png
diff --git a/frontend/src/assets/faidare/images/marker-icon-green.png b/backend/src/main/resources/static/resources/images/marker-icon-green.png
similarity index 100%
rename from frontend/src/assets/faidare/images/marker-icon-green.png
rename to backend/src/main/resources/static/resources/images/marker-icon-green.png
diff --git a/frontend/src/assets/faidare/images/marker-icon-purple.png b/backend/src/main/resources/static/resources/images/marker-icon-purple.png
similarity index 100%
rename from frontend/src/assets/faidare/images/marker-icon-purple.png
rename to backend/src/main/resources/static/resources/images/marker-icon-purple.png
diff --git a/frontend/src/assets/faidare/images/marker-icon-red.png b/backend/src/main/resources/static/resources/images/marker-icon-red.png
similarity index 100%
rename from frontend/src/assets/faidare/images/marker-icon-red.png
rename to backend/src/main/resources/static/resources/images/marker-icon-red.png
diff --git a/backend/src/main/resources/templates/error/4xx.html b/backend/src/main/resources/templates/error/4xx.html
new file mode 100644
index 0000000000000000000000000000000000000000..0a5464d9b840c4f356fbe171545f0c960d107dfb
--- /dev/null
+++ b/backend/src/main/resources/templates/error/4xx.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+<html
+  xmlns:th="http://www.thymeleaf.org"
+  th:replace="~{layout/main :: layout(title=~{::title}, content=~{::main}, script=~{})}"
+>
+  <head>
+    <title>Error</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+
+  <body>
+    <main>
+      <h1 class="display-1" th:text="${status}">404</h1>
+      <p th:if="${status == 404}">Sorry, the requested page does not exist.</p>
+      <p class="lead" th:if="${status != 404}">
+        Unexpected error: <span th:text="${error}">.</span>
+      </p>
+    </main>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/error/5xx.html b/backend/src/main/resources/templates/error/5xx.html
new file mode 100644
index 0000000000000000000000000000000000000000..462e086b74aed7d630db9cf716a04d3394edaaf4
--- /dev/null
+++ b/backend/src/main/resources/templates/error/5xx.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+<html
+  xmlns:th="http://www.thymeleaf.org"
+  th:replace="~{layout/main :: layout(title=~{::title}, content=~{::main}, script=~{})}"
+>
+  <head>
+    <title>Error</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+
+  <body>
+    <main>
+      <h1 class="display-1" th:text="${status}">404</h1>
+      <p class="lead">Unexpected error: <span th:text="${error}">.</span></p>
+    </main>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/fragments/institute.html b/backend/src/main/resources/templates/fragments/institute.html
new file mode 100644
index 0000000000000000000000000000000000000000..85871d5238adda8d38610de218a4b1654c4dce1a
--- /dev/null
+++ b/backend/src/main/resources/templates/fragments/institute.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+  <body>
+    <!--
+Reusable fragment displaying the content of an institute popover.
+Its unique argument (institute) is an InstituteVO
+-->
+
+    <th:block th:fragment="institute(institute)">
+      <div class="text-center py-2" th:if="${institute.logo}">
+        <img
+          class="img-fluid"
+          th:src="${institute.logo}"
+          th:alt="${institute.instituteName}"
+        />
+      </div>
+      <div
+        th:replace="fragments/row::text-row(label='Code', text=${institute.instituteCode})"
+      ></div>
+      <div
+        th:replace="fragments/row::text-row(label='Acronym', text=${institute.acronym})"
+      ></div>
+      <div
+        th:replace="fragments/row::text-row(label='Organization', text=${institute.organisation})"
+      ></div>
+      <div
+        th:replace="fragments/row::text-row(label='Type', text=${institute.instituteType})"
+      ></div>
+      <div
+        th:replace="fragments/row::text-row(label='Address', text=${institute.address})"
+      ></div>
+
+      <th:block th:if="${institute.webSite}">
+        <div
+          th:replace="fragments/row::row(label='Website', content=~{::.institute-website})"
+        >
+          <a
+            class="institute-website"
+            target="_blank"
+            th:href="${institute.webSite}"
+            th:text="${#strings.abbreviate(institute.webSite, 25)}"
+          ></a>
+        </div>
+      </th:block>
+    </th:block>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/fragments/link.html b/backend/src/main/resources/templates/fragments/link.html
new file mode 100644
index 0000000000000000000000000000000000000000..d82f0bd5c03a81844046044b6702e8e3e361d561
--- /dev/null
+++ b/backend/src/main/resources/templates/fragments/link.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+  <body>
+    <!--
+Reusable fragment displaying a link with a label if the provided url is not
+empty, or a span with the label if the provided url is empty.
+Both arguments are strings.
+-->
+    <th:block th:fragment="link(label, url)">
+      <a
+        th:unless="${#strings.isEmpty(url)}"
+        th:href="${url}"
+        th:text="${label}"
+      ></a>
+      <span th:if="${#strings.isEmpty(url)}" th:text="${label}"></span>
+    </th:block>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/fragments/map.html b/backend/src/main/resources/templates/fragments/map.html
new file mode 100644
index 0000000000000000000000000000000000000000..aa51b67ebc0b3fc023bf3d4062aad0b2b1e704f3
--- /dev/null
+++ b/backend/src/main/resources/templates/fragments/map.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+  <body>
+    <!--
+Reusable fragment displaying a map and its legend.
+The map is initially hidden. The JavaScript displays it if there are locations
+to display
+-->
+    <div th:fragment="map" id="map-container" class="d-none">
+      <div id="map" class="border rounded"></div>
+      <div class="map-legend mt-1 small">
+        <img th:src="@{/resources/images/marker-icon-red.png}" id="red" />
+        <label for="red" class="me-2">Origin site</label>
+        <img th:src="@{/resources/images/marker-icon-blue.png}" id="blue" />
+        <label for="blue" class="me-2">Collecting site</label>
+        <img th:src="@{/resources/images/marker-icon-green.png}" id="green" />
+        <label for="green" class="me-2">Evaluation site</label>
+        <img th:src="@{/resources/images/marker-icon-purple.png}" id="purple" />
+        <label for="purple">Multi-purpose site</label>
+      </div>
+    </div>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/fragments/row.html b/backend/src/main/resources/templates/fragments/row.html
new file mode 100644
index 0000000000000000000000000000000000000000..aebf2476a74cbb9d5cd3e1fb57fcdde5d331a462
--- /dev/null
+++ b/backend/src/main/resources/templates/fragments/row.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+  <body>
+    <!--
+Reusable fragment displaying a responsive row containing a label and a content.
+The label argument is a string.
+The content argument is a fragment which is displayed at the right of the label.
+
+Note that `th:if` is not evaluated when th:replace is used. So if this row must
+be displayed only if some condition is true, the fragment should be enclosed
+into a block with the condition:
+  <th:block th:if="${someCondition}">
+    <div th:replace="fragments/row::row(label='Some label', content=~{::#some-content-id})">
+      <span id="some-content-id">the content here</span>
+    </div>
+  </th:block>
+-->
+
+    <div th:fragment="row(label, content)" class="row f-row">
+      <div class="col-md-4 label pb-1 pb-md-0" th:text="${label}"></div>
+      <div class="col">
+        <th:block th:replace="${content}" />
+      </div>
+    </div>
+
+    <!--
+Reusable fragment displaying a responsive row containing a label and a textual content.
+The label argument is a string.
+The text argument is a string which is displayed at the right of the label.
+The whole row is omitted if the textual content is empty, so the caller does not
+need to test that condition.
+
+Note that `th:if` is not evaluated when th:replace is used. So if this row must
+be displayed only if some other condition is true, the fragment should be enclosed
+into a block with the condition:
+  <th:block th:if="${someCondition}">
+    <div th:replace="fragments/row::text-row(label='Some label', text=${someTextExpression})"></div>
+  </th:block>
+-->
+    <div
+      th:fragment="text-row(label, text)"
+      th:unless="${#strings.isEmpty(text)}"
+      class="row f-row"
+    >
+      <div class="col-md-4 label pb-1 pb-md-0" th:text="${label}"></div>
+      <div class="col" th:text="${text}"></div>
+    </div>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/fragments/source.html b/backend/src/main/resources/templates/fragments/source.html
new file mode 100644
index 0000000000000000000000000000000000000000..ad5e588c3d53e3ce096774e742d008f5110f44ec
--- /dev/null
+++ b/backend/src/main/resources/templates/fragments/source.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+  <body>
+    <!--
+Reusable fragment displaying the source and the data links of an entity (site, study or germplasm).
+The source argument is a DataSource.
+The url argument is a string, which is the URL of the entity.
+The entityType argument is a string, which is used in the message
+"Link to this <entityType>".
+-->
+
+    <th:block th:fragment="source(source, url, entityType)">
+      <th:block th:if="${source != null}">
+        <div
+          th:replace="fragments/row::row(label='Source', content=~{::.source})"
+        >
+          <a class="source" target="_blank" th:href="${source.url}">
+            <img
+              class="img-fluid"
+              style="max-height: 60px"
+              th:src="${source.image}"
+              th:alt="${source.name} + ' logo'"
+            />
+          </a>
+        </div>
+      </th:block>
+
+      <th:block th:if="${url != null && source != null}">
+        <div
+          th:replace="fragments/row::row(label='Data link', content=~{::.source-url})"
+        >
+          <a class="source-url" target="_blank" th:href="${url}">
+            Link to this <span th:text="${entityType}"></span> on
+            <th:block th:text="${source.name}" />
+          </a>
+        </div>
+      </th:block>
+    </th:block>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/fragments/xrefs.html b/backend/src/main/resources/templates/fragments/xrefs.html
new file mode 100644
index 0000000000000000000000000000000000000000..938d3ea6e96aeabb26d19290b4fe0fa132645e2e
--- /dev/null
+++ b/backend/src/main/resources/templates/fragments/xrefs.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+  <body>
+    <!--
+Reusable fragment displaying a cross references section, with its title.
+The unique argument (crossReferences) is a List<XRefDocumentVO>
+-->
+
+    <div
+      class="f-card"
+      th:fragment="xrefs(crossReferences)"
+      th:if="${!#lists.isEmpty(crossReferences)}"
+    >
+      <h2>Cross references</h2>
+      <div class="f-card-body">
+        <div class="scroll-table-container scroll-table-container-big">
+          <table
+            class="
+              table table-sm table-striped table-sticky table-responsive-sm
+            "
+          >
+            <thead>
+              <tr>
+                <th scope="col">Name</th>
+                <th scope="col">Source</th>
+                <th scope="col">Type</th>
+                <th scope="col">Description</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr th:each="crossRef : ${crossReferences}">
+                <td>
+                  <a
+                    th:href="${crossRef.url}"
+                    target="_blank"
+                    th:text="${crossRef.name}"
+                  ></a>
+                </td>
+                <td th:text="${crossRef.databaseName}"></td>
+                <td th:text="${crossRef.entryType}"></td>
+                <td
+                  style="min-width: 30rem"
+                  th:text="${#strings.abbreviate(crossRef.description, 120)}"
+                ></td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/germplasm.html b/backend/src/main/resources/templates/germplasm.html
new file mode 100644
index 0000000000000000000000000000000000000000..b4a9f9b14363cc85396e97f342731d730b7f5493
--- /dev/null
+++ b/backend/src/main/resources/templates/germplasm.html
@@ -0,0 +1,745 @@
+<!DOCTYPE html>
+
+<html
+  xmlns:th="http://www.thymeleaf.org"
+  th:replace="~{layout/main :: layout(title=~{::title}, content=~{::main}, script=~{::script})}"
+>
+  <head>
+    <title>
+      Germplasm: <th:block th:text="${model.germplasm.germplasmName}" />
+    </title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+
+  <body>
+    <main>
+      <div class="d-flex">
+        <h1 class="flex-grow-1">
+          Germplasm: <th:block th:text="${model.germplasm.germplasmName}" />
+        </h1>
+        <div
+          th:if="${model.germplasm.holdingGenbank != null && model.germplasm.holdingGenbank.logo != null}"
+        >
+          <img
+            th:src="${model.germplasm.holdingGenbank.logo}"
+            th:alt="${model.germplasm.holdingGenbank.instituteName}"
+          />
+        </div>
+      </div>
+
+      <div th:replace="fragments/map::map"></div>
+
+      <div class="row align-items-center justify-content-center mt-4">
+        <div
+          class="col-auto field"
+          th:if="${model.germplasm.photo != null && model.germplasm.photo.thumbnailFile != null}"
+        >
+          <template id="photo-popover">
+            <div class="card">
+              <img
+                th:src="${model.germplasm.photo.file}"
+                class="card-img-top"
+                alt=""
+              />
+              <div class="card-body">
+                <div
+                  th:replace="fragments/row::text-row(label='Accession name', text=${model.germplasm.germplasmName})"
+                ></div>
+                <div
+                  th:replace="fragments/row::text-row(label='Photo name', text=${model.germplasm.photo.photoName})"
+                ></div>
+                <div
+                  th:replace="fragments/row::text-row(label='Description', text=${model.germplasm.photo.description})"
+                ></div>
+                <div
+                  th:replace="fragments/row::text-row(label='Copyright', text=${model.germplasm.photo.copyright})"
+                ></div>
+              </div>
+            </div>
+          </template>
+
+          <a
+            role="button"
+            class="d-flex flex-column align-items-center"
+            data-bs-toggle="popover"
+            tabindex="0"
+            th:data-bs-title="${model.germplasm.photo.photoName}"
+            data-bs-element="#photo-popover"
+            data-bs-container="body"
+            data-bs-trigger="focus"
+          >
+            <img
+              th:src="${model.germplasm.photo.thumbnailFile}"
+              class="img-fluid"
+            />
+
+            <figcaption class="figure-caption">
+              © <span th:text="${model.germplasm.photo.copyright}"></span>
+            </figcaption>
+          </a>
+        </div>
+
+        <div class="col-12 col-lg">
+          <div class="f-card">
+            <h2>Identification</h2>
+
+            <div class="f-card-body">
+              <div
+                th:replace="fragments/row::text-row(label='Germplasm name', text=${model.germplasm.germplasmName})"
+              ></div>
+              <div
+                th:replace="fragments/row::text-row(label='Accession number', text=${model.germplasm.accessionNumber})"
+              ></div>
+              <div
+                th:replace="fragments/row::row(label='Germplasm PUI', content=~{::#germplasm-pui})"
+              >
+                <th:block id="germplasm-pui">
+                  <a
+                    th:if="${model.puiDisplayedAsLink}"
+                    th:href="${model.germplasm.germplasmPUI}"
+                    th:text="${model.germplasm.germplasmPUI}"
+                  ></a>
+                  <span
+                    th:unless="${model.puiDisplayedAsLink}"
+                    th:text="${model.germplasm.germplasmPUI}"
+                  ></span>
+                </th:block>
+              </div>
+
+              <div
+                th:replace="fragments/source::source(source=${model.source}, url=${model.germplasm.url}, entityType='germplasm')"
+              ></div>
+
+              <th:block th:unless="${#lists.isEmpty(model.germplasm.synonyms)}">
+                <div
+                  th:replace="fragments/row::row(label='Accession synonyms', content=~{::#accession-synonyms})"
+                >
+                  <div
+                    id="accession-synonyms"
+                    class="content-overflow"
+                    th:text="${#strings.listJoin(model.germplasm.synonyms, ', ')}"
+                  ></div>
+                </div>
+              </th:block>
+
+              <th:block th:unless="${#strings.isEmpty(model.taxon)}">
+                <div
+                  th:replace="fragments/row::row(label='Taxon', content=~{::#taxon})"
+                >
+                  <div id="taxon">
+                    <template id="taxon-popover">
+                      <th:block
+                        th:unless="${#strings.isEmpty(model.germplasm.genus)}"
+                      >
+                        <div
+                          th:replace="fragments/row::row(label='Genus', content=~{::#taxon-genus})"
+                        >
+                          <em
+                            id="taxon-genus"
+                            th:text="${model.germplasm.genus}"
+                          ></em>
+                        </div>
+                      </th:block>
+                      <th:block
+                        th:unless="${#strings.isEmpty(model.germplasm.species)}"
+                      >
+                        <div
+                          th:replace="fragments/row::row(label='Species', content=~{::#taxon-species})"
+                        >
+                          <span id="taxon-species">
+                            <em th:text="${model.germplasm.species}"></em>
+                            <span
+                              th:unless="${#strings.isEmpty(model.germplasm.speciesAuthority)}"
+                              th:text="${'(' + model.germplasm.speciesAuthority + ')'}"
+                            ></span>
+                          </span>
+                        </div>
+                      </th:block>
+                      <th:block
+                        th:unless="${#strings.isEmpty(model.germplasm.subtaxa)}"
+                      >
+                        <div
+                          th:replace="fragments/row::row(label='Subtaxa', content=~{::#taxon-subtaxa})"
+                        >
+                          <span id="taxon-subtaxa">
+                            <em th:text="${model.germplasm.subtaxa}"></em>
+                            <span
+                              th:unless="${#strings.isEmpty(model.germplasm.subtaxaAuthority)}"
+                              th:text="${'(' + model.germplasm.subtaxaAuthority + ')'}"
+                            ></span>
+                          </span>
+                        </div>
+                      </th:block>
+
+                      <div
+                        th:replace="fragments/row::text-row(label='Authority', text=${model.taxonAuthor})"
+                      ></div>
+
+                      <th:block
+                        th:unless="${#lists.isEmpty(model.germplasm.taxonIds)}"
+                      >
+                        <div
+                          th:replace="fragments/row::row(label='Taxon IDs', content=~{::#taxon-ids})"
+                        >
+                          <div id="taxon-ids">
+                            <div
+                              th:each="taxonId : ${model.germplasm.taxonIds}"
+                              class="row"
+                            >
+                              <div
+                                class="col-6 text-nowrap"
+                                th:text="${taxonId.sourceName}"
+                              ></div>
+                              <div class="col-6">
+                                <span
+                                  class="taxon-id"
+                                  th:replace="fragments/link::link(label=${taxonId.taxonId}, url=${#faidare.taxonIdUrl(taxonId)})"
+                                ></span>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                      </th:block>
+
+                      <div
+                        th:replace="fragments/row::text-row(label='Comment', text=${model.germplasm.taxonComment})"
+                      ></div>
+                      <th:block
+                        th:unless="${#lists.isEmpty(model.germplasm.taxonCommonNames)}"
+                      >
+                        <div
+                          th:replace="fragments/row::row(label='Taxon common names', content=~{::#taxon-common-names})"
+                        >
+                          <div
+                            id="taxon-common-names"
+                            class="content-overflow"
+                            th:text="${#strings.listJoin(model.germplasm.taxonCommonNames, ', ')}"
+                          ></div>
+                        </div>
+                      </th:block>
+                      <th:block
+                        th:unless="${#lists.isEmpty(model.germplasm.taxonSynonyms)}"
+                      >
+                        <div
+                          th:replace="fragments/row::row(label='Taxon synonyms', content=~{::#taxon-synonyms})"
+                        >
+                          <div
+                            id="taxon-synonyms"
+                            class="content-overflow"
+                            th:text="${#strings.listJoin(model.germplasm.taxonSynonyms, ', ')}"
+                          ></div>
+                        </div>
+                      </th:block>
+                    </template>
+                    <a
+                      role="button"
+                      tabindex="0"
+                      data-bs-toggle="popover"
+                      th:data-bs-title="${model.taxon}"
+                      data-bs-element="#taxon-popover"
+                      data-bs-container="body"
+                      data-bs-trigger="focus"
+                    >
+                      <em th:text="${model.taxon}"></em>
+                      <th:block
+                        th:unless="${#strings.isEmpty(model.taxonAuthor)}"
+                        >(<span th:text="${model.taxonAuthor}"></span
+                        >)</th:block
+                      >
+                    </a>
+                  </div>
+                </div>
+              </th:block>
+
+              <div
+                th:replace="fragments/row::text-row(label='Biological status', text=${model.germplasm.biologicalStatusOfAccessionCode})"
+              ></div>
+              <div
+                th:replace="fragments/row::text-row(label='Genetic nature', text=${model.germplasm.geneticNature})"
+              ></div>
+              <div
+                th:replace="fragments/row::text-row(label='Seed source', text=${model.germplasm.seedSource})"
+              ></div>
+              <div
+                th:replace="fragments/row::text-row(label='Pedigree', text=${model.germplasm.pedigree})"
+              ></div>
+              <div
+                th:replace="fragments/row::text-row(label='Comments', text=${model.germplasm.comment})"
+              ></div>
+
+              <th:block
+                th:if="${model.germplasm.originSite != null && !#strings.isEmpty(model.germplasm.originSite.siteName)}"
+              >
+                <div
+                  th:replace="fragments/row::row(label='Origin site', content=~{::#origin-site})"
+                >
+                  <a
+                    id="origin-site"
+                    th:href="@{/sites/{siteId}(siteId=${#faidare.toSiteParam(model.germplasm.originSite.siteId)})}"
+                    th:text="${model.germplasm.originSite.siteName}"
+                  ></a>
+                </div>
+              </th:block>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="f-card" th:if="${model.germplasm.holdingInstitute}">
+        <h2>Depositary</h2>
+        <div class="f-card-body">
+          <template id="holding-institute-popover">
+            <div
+              th:replace="fragments/institute::institute(institute=${model.germplasm.holdingInstitute})"
+            ></div>
+          </template>
+          <div
+            th:replace="fragments/row::row(label='Institution', content=~{::#institution})"
+          >
+            <a
+              id="institution"
+              role="button"
+              tabindex="0"
+              data-bs-toggle="popover"
+              th:data-bs-title="${model.germplasm.holdingInstitute.instituteName}"
+              data-bs-element="#holding-institute-popover"
+              data-bs-container="body"
+              data-bs-trigger="focus"
+              th:text="${model.germplasm.holdingInstitute.instituteName}"
+            ></a>
+          </div>
+
+          <th:block
+            th:if="${model.germplasm.holdingGenbank != null && !#strings.isEmpty(model.germplasm.holdingGenbank.instituteName) && !#strings.isEmpty(model.germplasm.holdingGenbank.webSite)}"
+          >
+            <div
+              th:replace="fragments/row::row(label='Stock center name', content=~{::#stock-center-name})"
+            >
+              <a
+                id="stock-center-name"
+                target="_blank"
+                th:href="${model.germplasm.holdingGenbank.webSite}"
+                th:text="${model.germplasm.holdingGenbank.instituteName}"
+              ></a>
+            </div>
+          </th:block>
+
+          <div
+            th:replace="fragments/row::text-row(label='Presence status', text=${model.germplasm.presenceStatus})"
+          ></div>
+        </div>
+      </div>
+
+      <div class="f-card" th:if="${model.collecting}">
+        <h2>Collector</h2>
+        <div class="f-card-body">
+          <th:block
+            th:if="${model.germplasm.collectingSite != null && !#strings.isEmpty(model.germplasm.collectingSite.siteName)}"
+          >
+            <div
+              th:replace="fragments/row::row(label='Collecting site', content=~{::#collecting-site})"
+            >
+              <a
+                id="collecting-site"
+                th:href="@{/sites/{siteId}(siteId=${#faidare.toSiteParam(model.germplasm.collectingSite.siteId)})}"
+                th:text="${model.germplasm.collectingSite.siteName}"
+              ></a>
+            </div>
+          </th:block>
+
+          <th:block th:if="${model.germplasm.collector != null}">
+            <div
+              th:replace="fragments/row::text-row(label='Material type', text=${model.germplasm.collector.materialType})"
+            ></div>
+            <div
+              th:replace="fragments/row::text-row(label='Collectors', text=${model.germplasm.collector.collectors})"
+            ></div>
+
+            <th:block
+              th:if="${!#strings.isEmpty(model.germplasm.acquisitionDate) && model.germplasm.collector.accessionCreationDate == null}"
+            >
+              <div
+                th:replace="fragments/row::text-row(label='Acquisition / Creation date', text=${model.germplasm.acquisitionDate})"
+              ></div>
+            </th:block>
+
+            <th:block
+              th:if="${model.germplasm.collector.institute != null && !#strings.isEmpty(model.germplasm.collector.institute.instituteName)}"
+            >
+              <template id="collector-institute-popover">
+                <div
+                  th:replace="fragments/institute::institute(institute=${model.germplasm.collector.institute})"
+                ></div>
+              </template>
+              <div
+                th:replace="fragments/row::row(label='Institution', content=~{::#collecting-institution})"
+              >
+                <a
+                  id="collecting-institution"
+                  role="button"
+                  tabindex="0"
+                  data-bs-toggle="popover"
+                  th:data-bs-title="${model.germplasm.collector.institute.instituteName}"
+                  data-bs-element="#collector-institute-popover"
+                  data-bs-container="body"
+                  data-bs-trigger="focus"
+                  th:text="${model.germplasm.collector.institute.instituteName}"
+                ></a>
+              </div>
+            </th:block>
+
+            <div
+              th:replace="fragments/row::text-row(label='Accession number', text=${model.germplasm.collector.accessionNumber})"
+            ></div>
+          </th:block>
+        </div>
+      </div>
+
+      <div class="f-card" th:if="${model.breeding}">
+        <h2>Breeder</h2>
+        <div class="f-card-body">
+          <th:block
+            th:if="${model.germplasm.breeder.institute != null && !#strings.isEmpty(model.germplasm.breeder.institute.instituteName)}"
+          >
+            <template id="breeder-institute-popover">
+              <div
+                th:replace="fragments/institute::institute(institute=${model.germplasm.breeder.institute})"
+              ></div>
+            </template>
+            <div
+              th:replace="fragments/row::row(label='Institute', content=~{::#breeding-institution})"
+            >
+              <a
+                id="breeding-institution"
+                role="button"
+                tabindex="0"
+                data-bs-toggle="popover"
+                th:data-bs-title="${model.germplasm.breeder.institute.instituteName}"
+                data-bs-element="#breeder-institute-popover"
+                data-bs-container="body"
+                data-bs-trigger="focus"
+                th:text="${model.germplasm.breeder.institute.instituteName}"
+              ></a>
+            </div>
+          </th:block>
+
+          <div
+            th:replace="fragments/row::text-row(label='Accession creation year', text=${model.germplasm.breeder.accessionCreationDate})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Accession number', text=${model.germplasm.breeder.accessionNumber})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Catalog registration year', text=${model.germplasm.breeder.registrationYear})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Catalog deregistration year', text=${model.germplasm.breeder.deregistrationYear})"
+          ></div>
+        </div>
+      </div>
+
+      <div class="f-card" th:unless="${#lists.isEmpty(model.germplasm.donors)}">
+        <h2>Donors</h2>
+        <div class="f-card-body">
+          <div class="scroll-table-container">
+            <table
+              class="table table-sm table-striped table-sticky table-responsive-sm"
+            >
+              <thead>
+                <tr>
+                  <th scope="col">Institute name</th>
+                  <th scope="col">Institute code</th>
+                  <th scope="col">Donation date</th>
+                  <th scope="col">Accession number</th>
+                  <th scope="col">Accession PUI</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr th:each="row, donorIterStat : ${model.germplasm.donors}">
+                  <td>
+                    <template
+                      th:id="${'donor-institute-popover-' + donorIterStat.index}"
+                    >
+                      <div
+                        th:replace="fragments/institute::institute(institute=${row.donorInstitute})"
+                      ></div>
+                    </template>
+                    <a
+                      role="button"
+                      tabindex="0"
+                      data-bs-toggle="popover"
+                      th:data-bs-title="${row.donorInstitute.instituteName}"
+                      th:data-bs-element="${'#donor-institute-popover-' + donorIterStat.index}"
+                      data-bs-container="body"
+                      data-bs-trigger="focus"
+                      th:text="${row.donorInstitute.instituteName}"
+                    ></a>
+                  </td>
+                  <td th:text="${row.donorInstituteCode}"></td>
+                  <td th:text="${row.donationDate}"></td>
+                  <td th:text="${row.donorAccessionNumber}"></td>
+                  <td th:text="${row.donorGermplasmPUI}"></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+
+      <div
+        class="f-card"
+        th:unless="${#lists.isEmpty(model.germplasm.distributors)}"
+      >
+        <h2>Distributors</h2>
+        <div class="f-card-body">
+          <div class="scroll-table-container">
+            <table
+              class="table table-sm table-striped table-sticky table-responsive-sm"
+            >
+              <thead>
+                <tr>
+                  <th scope="col">Institute</th>
+                  <th scope="col">Accession number</th>
+                  <th scope="col">Distribution status</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr
+                  th:each="row, distributorIterStat : ${model.germplasm.distributors}"
+                >
+                  <td>
+                    <template
+                      th:id="${'distributor-institute-popover-' + distributorIterStat.index}"
+                    >
+                      <div
+                        th:replace="fragments/institute::institute(institute=${row.institute})"
+                      ></div>
+                    </template>
+                    <a
+                      role="button"
+                      tabindex="0"
+                      th:data-bs-title="${row.institute.instituteName}"
+                      th:data-bs-element="${'#distributor-institute-popover-' + distributorIterStat.index}"
+                      data-bs-container="body"
+                      data-bs-trigger="focus"
+                      th:text="${row.institute.instituteName}"
+                    ></a>
+                  </td>
+                  <td th:text="${row.accessionNumber}"></td>
+                  <td th:text="${row.distributionStatus}"></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+
+      <div class="f-card" th:unless="${#lists.isEmpty(model.attributes)}">
+        <h2>Evaluation Data</h2>
+        <div class="f-card-body">
+          <th:block th:each="descriptor : ${model.attributes}">
+            <div
+              th:replace="fragments/row::text-row(label=${descriptor.attributeName}, text=${descriptor.value})"
+            ></div>
+          </th:block>
+        </div>
+      </div>
+
+      <div class="f-card" th:if="${model.genealogyPresent}">
+        <h2>Genealogy</h2>
+        <div class="f-card-body">
+          <th:block th:if="${model.pedigree != null}">
+            <div
+              th:replace="fragments/row::text-row(label='Crossing plan', text=${model.pedigree.crossingPlan})"
+            ></div>
+            <div
+              th:replace="fragments/row::text-row(label='Crossing year', text=${model.pedigree.crossingYear})"
+            ></div>
+            <div
+              th:replace="fragments/row::text-row(label='Family code', text=${model.pedigree.familyCode})"
+            ></div>
+            <th:block
+              th:unless="${#strings.isEmpty(model.pedigree.parent1Name)}"
+            >
+              <div
+                th:replace="fragments/row::row(label='Parent accessions', content=~{::#parent-accessions})"
+              >
+                <div id="parent-accessions">
+                  <th:block th:if="${model.pedigree.parent1DbId}">
+                    <div
+                      th:replace="fragments/row::row(label=${model.pedigree.parent1Type}, content=~{::#parent1-link})"
+                    >
+                      <a
+                        id="parent1-link"
+                        th:href="@{/germplasms/{germplasmId}(germplasmId=${model.pedigree.parent1DbId})}"
+                        th:text="${model.pedigree.parent1Name}"
+                      ></a>
+                    </div>
+                  </th:block>
+
+                  <th:block th:if="${model.pedigree.parent2DbId}">
+                    <div
+                      th:replace="fragments/row::row(label=${model.pedigree.parent2Type}, content=~{::#parent2-link})"
+                    >
+                      <a
+                        id="parent2-link"
+                        th:href="@{/germplasms/{germplasmId}(germplasmId=${model.pedigree.parent2DbId})}"
+                        th:text="${model.pedigree.parent2Name}"
+                      ></a>
+                    </div>
+                  </th:block>
+                </div>
+              </div>
+            </th:block>
+
+            <th:block th:unless="${#lists.isEmpty(model.pedigree.siblings)}">
+              <div
+                th:replace="fragments/row::row(label='Sibling accessions', content=~{::#sibling-accessions})"
+              >
+                <div id="sibling-accessions" class="content-overflow">
+                  <a
+                    th:each="sibling : ${model.pedigree.siblings}"
+                    th:href="@{/germplasms/{germplasmId}(germplasmId=${sibling.germplasmDbId})}"
+                    th:text="${sibling.defaultDisplayName}"
+                  ></a>
+                </div>
+              </div>
+            </th:block>
+          </th:block>
+
+          <th:block th:unless="${#lists.isEmpty(model.germplasm.children)}">
+            <div
+              th:replace="fragments/row::row(label='Descendants', content=~{::#descendants})"
+            >
+              <div
+                id="descendants"
+                class="content-overflow content-overflow-big"
+              >
+                <th:block th:each="child : ${model.germplasm.children}">
+                  <div
+                    th:replace="fragments/row::row(label=${#strings.isEmpty(child.secondParentName) ? ('children of ' + child.firstParentName) : ('children of ' + child.firstParentName + ' x ' + child.secondParentName) }, content=~{::.descendant-child})"
+                  >
+                    <div class="descendant-child">
+                      <th:block
+                        th:each="sibling, siblingIterStat : ${child.sibblings}"
+                      >
+                        <a
+                          th:href="@{/germplasms(pui=${sibling.pui})}"
+                          th:text="${sibling.name}"
+                        ></a
+                        ><th:block th:unless="${siblingIterStat.last}"
+                          >,
+                        </th:block>
+                      </th:block>
+                    </div>
+                  </div>
+                </th:block>
+              </div>
+            </div>
+          </th:block>
+        </div>
+      </div>
+
+      <div
+        class="f-card"
+        th:unless="${#lists.isEmpty(model.germplasm.population)}"
+      >
+        <h2>Population</h2>
+        <div class="f-card-body">
+          <th:block th:each="population : ${model.germplasm.population}">
+            <th:block th:if="${population.germplasmRef != null}">
+              <th:block
+                th:unless="${#strings.isEmpty(population.germplasmRef.pui)}"
+              >
+                <div
+                  th:replace="fragments/row::row(label=${#faidare.collPopTitle(population)}, content=~{::.population-1})"
+                >
+                  <div class="population-1">
+                    <a
+                      th:if="${population.germplasmRef.pui != model.germplasm.germplasmPUI}"
+                      th:href="@{/germplasms(pui=${population.germplasmRef.pui})}"
+                      th:text="${population.germplasmRef.name}"
+                    ></a>
+                    <span
+                      th:if="${population.germplasmRef.pui == model.germplasm.germplasmPUI}"
+                      th:text="${population.germplasmRef.name}"
+                    ></span>
+                    is composed by
+                    <a
+                      th:href="@{${#faidare.searchUrl()}(gl=${population.name},entry='Germplasm')}"
+                      th:text="${population.germplasmCount + ' accession(s)'}"
+                    ></a>
+                  </div>
+                </div>
+              </th:block>
+            </th:block>
+
+            <th:block th:if="${population.germplasmRef == null}">
+              <div
+                th:replace="fragments/row::row(label=${#faidare.collPopTitle(population)}, content=~{::.population-2})"
+              >
+                <div class="population-2">
+                  <a
+                    th:href="@{${#faidare.searchUrl()}(gl=${population.name},entry='Germplasm')}"
+                    th:text="${population.germplasmCount + ' accession(s)'}"
+                  ></a>
+                </div>
+              </div>
+            </th:block>
+          </th:block>
+        </div>
+      </div>
+
+      <div
+        class="f-card"
+        th:unless="${#lists.isEmpty(model.germplasm.collection)}"
+      >
+        <h2>Collection</h2>
+        <div class="f-card-body">
+          <th:block th:each="collection : ${model.germplasm.collection}">
+            <div
+              th:replace="fragments/row::row(label=${#faidare.collPopTitle(collection)}, content=~{::.collection})"
+            >
+              <div class="collection">
+                <a
+                  th:href="@{${#faidare.searchUrl()}(gl=${collection.name},entry='Germplasm')}"
+                  th:text="${collection.germplasmCount + ' accession(s)'}"
+                ></a>
+              </div>
+            </div>
+          </th:block>
+        </div>
+      </div>
+
+      <div class="f-card" th:unless="${#lists.isEmpty(model.germplasm.panel)}">
+        <h2>Panel</h2>
+        <div class="f-card-body">
+          <th:block th:each="panel : ${model.germplasm.panel}">
+            <div
+              th:replace="fragments/row::row(label=${#faidare.collPopTitleWithoutUnderscores(panel)}, content=~{::.panel})"
+            >
+              <div class="panel">
+                <a
+                  th:href="@{${#faidare.searchUrl()}(gl=${panel.name},entry='Germplasm')}"
+                  th:text="${panel.germplasmCount + ' accession(s)'}"
+                ></a>
+              </div>
+            </div>
+          </th:block>
+        </div>
+      </div>
+
+      <div
+        th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"
+      ></div>
+    </main>
+
+    <script th:inline="javascript">
+      faidare.initializePopovers();
+      faidare.initializeMap({
+        contextPath: [[${#request.getContextPath()}]],
+        locations: [[${model.mapLocations}]]
+      });
+    </script>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/index.html b/backend/src/main/resources/templates/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..2130bf93d95928eeb7711d61e3cecfbe42a37742
--- /dev/null
+++ b/backend/src/main/resources/templates/index.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+
+<html
+  xmlns:th="http://www.thymeleaf.org"
+  th:replace="~{layout/main :: layout(title=~{::title}, content=~{::main}, script=~{})}"
+>
+  <head>
+    <title>Faidare</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+
+  <body>
+    <main>
+      <h1>Welcome to Faidare</h1>
+    </main>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/layout/main.html b/backend/src/main/resources/templates/layout/main.html
new file mode 100644
index 0000000000000000000000000000000000000000..7b1bb775d55f36e7445153370ed12a73ca14b209
--- /dev/null
+++ b/backend/src/main/resources/templates/layout/main.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html
+  lang="fr"
+  th:fragment="layout (title, content, script)"
+  xmlns:th="http://www.thymeleaf.org"
+>
+  <head>
+    <title th:replace="${title}">Layout Title</title>
+
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta content="width=device-width, initial-scale=1" name="viewport" />
+
+    <link th:href="@{/resources/style.css}" rel="stylesheet" />
+
+    <link
+      rel="shortcut icon"
+      th:href="@{/resources/images/favicon.ico}"
+      type="image/x-icon"
+    />
+  </head>
+
+  <body>
+    <nav class="navbar navbar-expand-lg navbar-light bg-light">
+      <div class="container">
+        <a
+          class="navbar-brand py-0"
+          href="https://urgi.versailles.inrae.fr/faidare"
+        >
+          <img th:src="@{/resources/images/logo.png}" style="height: 40px" />
+        </a>
+        <button
+          class="navbar-toggler"
+          type="button"
+          data-bs-toggle="collapse"
+          data-bs-target="#navbarContent"
+          aria-controls="navbarContent"
+          aria-expanded="false"
+          aria-label="Toggle navigation"
+        >
+          <span class="navbar-toggler-icon"></span>
+        </button>
+        <div class="collapse navbar-collapse" id="navbarContent">
+          <ul class="navbar-nav me-auto">
+            <th:block th:each="topEntry : ${#faidare.navbarEntries}">
+              <li class="nav-item" th:if="${#lists.isEmpty(topEntry.subMenu)}">
+                <a
+                  class="nav-link"
+                  th:href="${topEntry.url}"
+                  th:text="${topEntry.label}"
+                ></a>
+              </li>
+              <li
+                class="nav-item dropdown"
+                th:if="${not #lists.isEmpty(topEntry.subMenu)}"
+              >
+                <a
+                  class="nav-link dropdown-toggle"
+                  th:id="${'navbar-dropdown-' + topEntry.label}"
+                  href="#"
+                  role="button"
+                  data-bs-toggle="dropdown"
+                  aria-expanded="false"
+                  th:text="${topEntry.label}"
+                >
+                </a>
+                <ul
+                  class="dropdown-menu bg-light"
+                  th:aria-labelledby="${'navbar-dropdown-' + topEntry.label}"
+                >
+                  <li th:each="subEntry : ${topEntry.subMenu}" class="bg-light">
+                    <a
+                      class="dropdown-item"
+                      th:href="${subEntry.url}"
+                      th:text="${subEntry.label}"
+                    ></a>
+                  </li>
+                </ul>
+              </li>
+            </th:block>
+          </ul>
+        </div>
+      </div>
+    </nav>
+    <div class="container mt-3">
+      <div th:replace="${content}">
+        <p>Layout content</p>
+      </div>
+    </div>
+    <script type="text/javascript" th:src="@{/resources/script.js}"></script>
+    <script type="text/javascript" th:replace="${script}"></script>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/site.html b/backend/src/main/resources/templates/site.html
new file mode 100644
index 0000000000000000000000000000000000000000..586affe043f0c5dfbf5c3dbc5901dd24698f47b1
--- /dev/null
+++ b/backend/src/main/resources/templates/site.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+
+<html
+  xmlns:th="http://www.thymeleaf.org"
+  th:replace="~{layout/main :: layout(title=~{::title}, content=~{::main}, script=~{::script})}"
+>
+  <head>
+    <title>Site <th:block th:text="${model.site.locationName}" /></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+
+  <body>
+    <main>
+      <h1>Site <th:block th:text="${model.site.locationName}" /></h1>
+
+      <div th:replace="fragments/map::map"></div>
+
+      <div class="f-card mt-4">
+        <h2>Details</h2>
+        <div class="f-card-body">
+          <th:block
+            th:if="${model.site.uri != null && !model.site.uri.startsWith('urn:')}"
+          >
+            <div
+              th:replace="fragments/row::text-row(label='Permanent unique identifier', text=${model.site.uri})"
+            ></div>
+          </th:block>
+
+          <div
+            th:replace="fragments/source::source(source=${model.source}, url=${model.site.url}, entityType='site')"
+          ></div>
+
+          <div
+            th:replace="fragments/row::text-row(label='Abbreviation', text=${model.site.abbreviation})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Type', text=${model.site.locationType})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Status', text=${model.siteStatus})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Institution/Landowner', text=${model.site.instituteName})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Institution address', text=${model.site.instituteAddress})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Coordinates precision', text=${model.coordinatesPrecision})"
+          ></div>
+          <th:block th:if="${model.site.latitude}">
+            <div
+              th:replace="fragments/row::text-row(label='Latitude', text=${#coordinates.formatLatitude(model.site.latitude)})"
+            ></div>
+          </th:block>
+          <th:block th:if="${model.site.longitude}">
+            <div
+              th:replace="fragments/row::text-row(label='Longitude', text=${#coordinates.formatLongitude(model.site.longitude)})"
+            ></div>
+          </th:block>
+          <div
+            th:replace="fragments/row::text-row(label='Geographical location', text=${model.geographicalLocation})"
+          ></div>
+          <th:block
+            th:if="${model.site.countryName != null && model.geographicalLocation == null}"
+          >
+            <div
+              th:replace="fragments/row::text-row(label='Country name', text=${model.site.countryName})"
+            ></div>
+          </th:block>
+
+          <th:block
+            th:if="${model.site.countryCode != null && model.geographicalLocation == null}"
+          >
+            <div
+              th:replace="fragments/row::text-row(label='Country code', text=${model.site.countryName})"
+            ></div>
+          </th:block>
+
+          <div
+            th:replace="fragments/row::text-row(label='Altitude', text=${model.site.altitude})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Slope', text=${model.slope})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Exposure', text=${model.exposure})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Topography', text=${model.topography})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Environment type', text=${model.environmentType})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Distance to city', text=${model.distanceToCity})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Direction from city', text=${model.directionFromCity})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Comment', text=${model.comment})"
+          ></div>
+        </div>
+      </div>
+
+      <div
+        class="f-card"
+        th:unless="${#lists.isEmpty(model.additionalInfoProperties)}"
+      >
+        <h2>Additional info</h2>
+        <div class="f-card-body">
+          <th:block th:each="prop : ${model.additionalInfoProperties}">
+            <div
+              th:replace="fragments/row::text-row(label=${prop.key}, text=${prop.value})"
+            ></div>
+          </th:block>
+        </div>
+      </div>
+
+      <div
+        th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"
+      ></div>
+    </main>
+
+    <script th:inline="javascript">
+      faidare.initializeMap({
+        contextPath: [[${#request.getContextPath()}]],
+        locations: [[${model.mapLocations}]]
+      });
+    </script>
+  </body>
+</html>
diff --git a/backend/src/main/resources/templates/study.html b/backend/src/main/resources/templates/study.html
new file mode 100644
index 0000000000000000000000000000000000000000..72d2a2486fc91a64ce1b0cc71cf2974fc1c259d5
--- /dev/null
+++ b/backend/src/main/resources/templates/study.html
@@ -0,0 +1,297 @@
+<!DOCTYPE html>
+
+<html
+  xmlns:th="http://www.thymeleaf.org"
+  th:replace="~{layout/main :: layout(title=~{::title}, content=~{::main}, script=~{::script})}"
+>
+  <head>
+    <title>
+      Study <th:block th:text="${model.study.studyType}" />: <th:block
+      th:text="${model.study.studyName}" />
+    </title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+
+  <body>
+    <main>
+      <h1>
+        Study <th:block th:text="${model.study.studyType}" />:
+        <th:block th:text="${model.study.studyName}" />
+      </h1>
+
+      <div th:replace="fragments/map::map"></div>
+
+      <div class="f-card mt-4">
+        <h2>Identification</h2>
+        <div class="f-card-body">
+          <div
+            th:replace="fragments/row::text-row(label='Name', text=${model.study.studyName})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Identifier', text=${model.study.studyDbId})"
+          ></div>
+
+          <div
+            th:replace="fragments/source::source(source=${model.source}, url=${model.study.url}, entityType='study')"
+          ></div>
+
+          <div
+            th:replace="fragments/row::text-row(label='Project name', text=${model.study.programName})"
+          ></div>
+          <div
+            th:replace="fragments/row::text-row(label='Description', text=${model.study.studyDescription})"
+          ></div>
+          <th:block th:if="${model.study.active != null}">
+            <div
+              th:replace="fragments/row::text-row(label='Active', text=${model.study.active ? 'Yes' : 'No'})"
+            ></div>
+          </th:block>
+
+          <th:block th:unless="${#lists.isEmpty(model.study.seasons)}">
+            <div
+              th:replace="fragments/row::text-row(label='Seasons', text=${#strings.listJoin(model.study.seasons, ',')})"
+            ></div>
+          </th:block>
+          <th:block
+            th:if="${model.study.startDate != null && model.study.endDate != null}"
+          >
+            <div
+              th:replace="fragments/row::text-row(label='Date', text=${'From ' + #dates.format(model.study.startDate, 'yyyy-MM-dd') + ' to ' + #dates.format(model.study.endDate, 'yyyy-MM-dd') })"
+            ></div>
+          </th:block>
+          <th:block
+            th:if="${model.study.startDate != null && model.study.endDate == null}"
+          >
+            <div
+              th:replace="fragments/row::text-row(label='Date', text=${'Started on ' + #dates.format(model.study.startDate, 'yyyy-MM-dd')})"
+            ></div>
+          </th:block>
+
+          <th:block th:if="${model.study.locationDbId}">
+            <div
+              th:replace="fragments/row::row(label='Location name', content=~{::#location})"
+            >
+              <a
+                id="location"
+                th:href="@{/sites/{siteId}(siteId=${model.study.locationDbId})}"
+                th:text="${model.study.locationName}"
+              ></a>
+            </div>
+          </th:block>
+
+          <th:block th:unless="${#lists.isEmpty(model.study.dataLinks)}">
+            <div
+              th:replace="fragments/row::row(label='Data files', content=~{::#data-files})"
+            >
+              <ul id="data-files" class="list-unstyled">
+                <li th:each="dataLink : ${model.study.dataLinks}">
+                  <a
+                    target="_blank"
+                    th:href="${dataLink.url}"
+                    th:text="${dataLink.name}"
+                  ></a>
+                </li>
+              </ul>
+            </div>
+          </th:block>
+        </div>
+      </div>
+
+      <div class="f-card" th:unles="${#lists.isEmpty(model.germplasms)}">
+        <h2>Genotype</h2>
+        <div class="f-card-body">
+          <div class="scroll-table-container scroll-table-container-big">
+            <table
+              class="
+                table table-sm table-striped table-sticky table-responsive-sm
+              "
+            >
+              <thead>
+                <tr>
+                  <th scope="col">Accession number</th>
+                  <th scope="col">Name</th>
+                  <th scope="col">Taxon</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr th:each="row : ${model.germplasms}">
+                  <td>
+                    <a
+                      th:href="@{/germplasms/{germplasmId}(germplasmId=${row.germplasmDbId})}"
+                      th:text="${row.accessionNumber}"
+                    ></a>
+                  </td>
+                  <td th:text="${row.germplasmName}"></td>
+                  <td
+                    th:text="${(row.genus == null ? '' : row.genus) + ' ' + (row.species == null ? '' : row.species)+ ' ' + (row.subtaxa == null ? '' : row.subtaxa) }"
+                  ></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+
+      <div class="f-card" th:unless="${#lists.isEmpty(model.variables)}">
+        <h2>Variables</h2>
+        <div class="f-card-body">
+          <div class="scroll-table-container">
+            <table
+              class="
+                table table-sm table-striped table-sticky table-responsive-sm
+              "
+            >
+              <thead>
+                <tr>
+                  <th scope="col">Variable ID</th>
+                  <th scope="col">Variable short name</th>
+                  <th scope="col">Variable long name</th>
+                  <th scope="col">Ontology name</th>
+                  <th scope="col">Trait description</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr th:each="row : ${model.variables}">
+                  <td>
+                    <a
+                      th:unless="${#strings.isEmpty(row.documentationURL)}"
+                      th:href="${row.documentationURL}"
+                      th:text="${row.observationVariableDbId}"
+                      target="_blank"
+                    ></a>
+                    <span
+                      th:if="${#strings.isEmpty(row.documentationURL)}"
+                      th:text="${row.observationVariableDbId}"
+                    ></span>
+                  </td>
+                  <td th:text="${row.name}"></td>
+                  <td
+                    th:text="${#lists.isEmpty(row.synonyms) ? '' : row.synonyms[0]}"
+                  ></td>
+                  <td th:text="${row.ontologyName}"></td>
+                  <td th:text="${row.trait.description}"></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+
+      <div class="f-card" th:unless="${#lists.isEmpty(model.trials)}">
+        <h2>Data Set</h2>
+        <div class="f-card-body">
+          <div class="scroll-table-container scroll-table-container-big">
+            <table
+              class="
+                table table-sm table-striped table-sticky table-responsive-sm
+              "
+            >
+              <thead>
+                <tr>
+                  <th scope="col">Name</th>
+                  <th scope="col">Type</th>
+                  <th scope="col">Linked studies identifier</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr th:each="row : ${model.trials}">
+                  <td>
+                    <a
+                      th:unless="${#strings.isEmpty(row.documentationURL)}"
+                      th:href="${row.documentationURL}"
+                      th:text="${row.trialName}"
+                      target="_blank"
+                    ></a>
+                    <span
+                      th:if="${#strings.isEmpty(row.documentationURL)}"
+                      th:text="${row.trialName}"
+                    ></span>
+                  </td>
+                  <td th:text="${row.trialType}"></td>
+                  <td style="width: 60%">
+                    <th:block
+                      th:each="trialStudy, iterStat : ${row.studies}"
+                      th:if="${trialStudy.studyDbId != model.study.studyDbId}"
+                    >
+                      <a
+                        th:href="@{/studies/{studyId}(studyId=${trialStudy.studyDbId})}"
+                        th:text="${trialStudy.studyName.trim()}"
+                      >
+                      </a
+                      ><th:block th:if="${iterStat.last}">; </th:block>
+                    </th:block>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+
+      <div class="f-card" th:unless="${#lists.isEmpty(model.study.contacts)}">
+        <h2>Contact</h2>
+        <div class="f-card-body">
+          <div class="scroll-table-container">
+            <table
+              class="
+                table table-sm table-striped table-sticky table-responsive-sm
+              "
+            >
+              <thead>
+                <tr>
+                  <th scope="col">Role</th>
+                  <th scope="col">Name</th>
+                  <th scope="col">Email</th>
+                  <th scope="col">Institution</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr th:each="row : ${model.study.contacts}">
+                  <td th:text="${row.type}"></td>
+                  <td th:text="${row.name}"></td>
+                  <td th:text="${row.email}"></td>
+                  <td th:text="${row.instituteName}"></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+
+      <div
+        class="f-card"
+        th:unless="${#lists.isEmpty(model.additionalInfoProperties)}"
+      >
+        <h2>Additional information</h2>
+        <div class="f-card-body">
+          <div class="scroll-table-container">
+            <table class="table table-sm">
+              <tbody>
+                <tr th:each="row : ${model.additionalInfoProperties}">
+                  <th
+                    class="label"
+                    style="width: 33.33%"
+                    th:text="${row.key}"
+                    scope="row"
+                  ></th>
+                  <td th:text="${row.value}"></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </div>
+
+      <div
+        th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"
+      ></div>
+    </main>
+
+    <script th:inline="javascript">
+      faidare.initializeMap({
+        contextPath: [[${#request.getContextPath()}]],
+        locations: [[${model.mapLocations}]]
+      });
+    </script>
+  </body>
+</html>
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/BrapiExceptionHandlerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/BrapiExceptionHandlerTest.java
index d395c9d015d77d639b806c1d2cd3ec0fa39580d3..e606f6979efd60e22d61b002a2f029fe19132a72 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/BrapiExceptionHandlerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/BrapiExceptionHandlerTest.java
@@ -33,8 +33,7 @@ class BrapiExceptionHandlerTest {
 
     @Test
     void should_Throw_Pagination_Max_Size_Exception() throws Exception {
-        mockMvc.perform(get("/brapi/v1/germplasm?pageSize=99999")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm?pageSize=99999"))
             .andExpect(status().isBadRequest())
             .andExpect(content().json("{\n" +
                 "  \"metadata\": {\n" +
@@ -61,8 +60,7 @@ class BrapiExceptionHandlerTest {
 
     @Test
     void should_Throw_Pagination_Min_Size_Exception() throws Exception {
-        mockMvc.perform(get("/brapi/v1/germplasm?pageSize=-1")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm?pageSize=-1"))
             .andExpect(status().isBadRequest())
             .andExpect(content().json("{\n" +
                 "  \"metadata\": {\n" +
@@ -85,8 +83,7 @@ class BrapiExceptionHandlerTest {
 
     @Test
     void should_Throw_Pagination_Min_Page_Exception() throws Exception {
-        mockMvc.perform(get("/brapi/v1/germplasm?page=-1")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm?page=-1"))
             .andExpect(status().isBadRequest())
             .andExpect(content().json("{\n" +
                 "  \"metadata\": {\n" +
@@ -108,8 +105,7 @@ class BrapiExceptionHandlerTest {
 
     @Test
     void should_Throw_Invalid_Param_Value_Exception() throws Exception {
-        mockMvc.perform(get("/brapi/v1/germplasm?page=foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm?page=foo"))
             .andExpect(status().isBadRequest())
             .andExpect(content().json("{\n" +
                 "  \"metadata\": {\n" +
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/CallsControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/CallsControllerTest.java
index 9bceca30daaf8da241f439d0585e37d3e3eacebc..73c08d4acd51a331c6dd49d1c49601462da233f3 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/CallsControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/CallsControllerTest.java
@@ -28,8 +28,7 @@ class CallsControllerTest {
     @Test
     void should_Get_Page_Size() throws Exception {
         int pageSize = 3;
-        mockMvc.perform(get("/brapi/v1/calls?pageSize=" + pageSize)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/calls?pageSize=" + pageSize))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.metadata.status", hasSize(0)))
             .andExpect(jsonPath("$.result.data", hasSize(pageSize)));
@@ -37,8 +36,7 @@ class CallsControllerTest {
 
     @Test
     void should_Fail_Page_Overflow() throws Exception {
-        mockMvc.perform(get("/brapi/v1/calls?pageSize=100&page=2")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/calls?pageSize=100&page=2"))
             .andExpect(status().isBadRequest())
             .andExpect(content().json("{" +
                 "\"metadata\":{" +
@@ -56,8 +54,7 @@ class CallsControllerTest {
 
     @Test
     void should_Get_All() throws Exception {
-        mockMvc.perform(get("/brapi/v1/calls?pageSize=1000")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/calls?pageSize=1000"))
             .andExpect(status().isOk())
             .andExpect(content().json("{\n" +
                 "  \"metadata\": {\n" +
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmControllerTest.java
index 3a0011514394260fe8e2310743087d43fdf90ebe..ec28b1a29d5b8b1c41bd8cd72fb0e3d2ab73bc5c 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/GermplasmControllerTest.java
@@ -54,8 +54,7 @@ class GermplasmControllerTest {
     void should_Not_Show_JSON_LD_Fields_By_Default() throws Exception {
         when(service.getById(anyString())).thenReturn(GERMPLASM);
 
-        mockMvc.perform(get("/brapi/v1/germplasm/" + GERMPLASM.getGermplasmDbId())
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm/" + GERMPLASM.getGermplasmDbId()))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id").doesNotExist());
     }
@@ -65,8 +64,7 @@ class GermplasmControllerTest {
         when(service.getById(anyString())).thenReturn(GERMPLASM);
 
         mockMvc.perform(get("/brapi/v1/germplasm/"+GERMPLASM.getGermplasmDbId())
-            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+                            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id", is(GERMPLASM.getUri())));
     }
@@ -76,8 +74,7 @@ class GermplasmControllerTest {
         ProgenyVO progeny = new ProgenyVO();
         when(service.getProgeny(anyString())).thenReturn(progeny);
 
-        mockMvc.perform(get("/brapi/v1/germplasm/Z25waXNfcHVpOnVua25vd246UmljZToxNjc4MzEw/progeny")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm/Z25waXNfcHVpOnVua25vd246UmljZToxNjc4MzEw/progeny"))
             .andExpect(status().isOk());
     }
 
@@ -86,8 +83,7 @@ class GermplasmControllerTest {
         GermplasmVO germplasm = new GermplasmVO();
         when(service.getById(anyString())).thenReturn(germplasm);
 
-        mockMvc.perform(get("/brapi/v1/germplasm/Z25waXNfcHVpOnVua25vd246UmljZToxNjc4MzEw")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm/Z25waXNfcHVpOnVua25vd246UmljZToxNjc4MzEw"))
             .andExpect(status().isOk());
     }
 
@@ -95,8 +91,7 @@ class GermplasmControllerTest {
     void should_Return_Not_Found() throws Exception {
         when(service.getById(anyString())).thenReturn(null);
 
-        mockMvc.perform(get("/brapi/v1/germplasm/foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm/foo"))
             .andExpect(status().isNotFound())
             .andExpect(jsonPath("$.metadata.status", hasSize(1)))
             .andExpect(jsonPath("$.metadata.status[0].code", is("404")));
@@ -122,9 +117,7 @@ class GermplasmControllerTest {
 
         when(service.getById(anyString())).thenReturn(germplasm);
 
-        mockMvc.perform(get("/brapi/v1/germplasm/foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
-
+        mockMvc.perform(get("/brapi/v1/germplasm/foo"))
             // Should not have private fields
             .andExpect(jsonPath("$.result", not(hasProperty("groupId"))))
             .andExpect(jsonPath("$.result", not(hasProperty("speciesGroup"))))
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/LocationControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/LocationControllerTest.java
index 256292d8c8d1d63b959b0b7c36fb8f838d739a3f..3f41729253c114cb26823ca7bf609c80d68ea4c2 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/LocationControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/LocationControllerTest.java
@@ -45,8 +45,7 @@ class LocationControllerTest {
     void should_Not_Show_JSON_LD_Fields_By_Default() throws Exception {
         when(repository.getById(LOCATION.getLocationDbId())).thenReturn(LOCATION);
 
-        mockMvc.perform(get("/brapi/v1/locations/" + LOCATION.getLocationDbId())
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/locations/" + LOCATION.getLocationDbId()))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id").doesNotExist());
     }
@@ -56,8 +55,7 @@ class LocationControllerTest {
         when(repository.getById(LOCATION.getLocationDbId())).thenReturn(LOCATION);
 
         mockMvc.perform(get("/brapi/v1/locations/"+LOCATION.getLocationDbId())
-            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+                            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id", is(LOCATION.getUri())));
     }
@@ -69,8 +67,7 @@ class LocationControllerTest {
         LocationVO location = new LocationVO();
         when(repository.getById(identifier)).thenReturn(location);
 
-        mockMvc.perform(get("/brapi/v1/locations/" + identifier)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/locations/" + identifier))
             .andExpect(status().isOk());
     }
 
@@ -78,8 +75,7 @@ class LocationControllerTest {
     void should_Return_Not_Found() throws Exception {
         when(repository.getById("foo")).thenReturn(null);
 
-        mockMvc.perform(get("/brapi/v1/locations/foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/locations/foo"))
             .andExpect(status().isNotFound())
             .andExpect(jsonPath("$.metadata.status", hasSize(1)))
             .andExpect(jsonPath("$.metadata.status[0].code", is("404")));
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableControllerTest.java
index bec00d617cb13a836d8a097e401300acf19f6f9c..5a7863aaa6bd7527a4ee1eacefa27ecae1103079 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ObservationVariableControllerTest.java
@@ -43,8 +43,7 @@ class ObservationVariableControllerTest {
     @Test
     void should_Not_Show_JSON_LD_Fields_By_Default() throws Exception {
         when(repository.getVariableById(VARIABLE.getObservationVariableDbId())).thenReturn(VARIABLE);
-        mockMvc.perform(get("/brapi/v1/variables/" + VARIABLE.getObservationVariableDbId())
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/variables/" + VARIABLE.getObservationVariableDbId()))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id").doesNotExist());
     }
@@ -54,8 +53,7 @@ class ObservationVariableControllerTest {
         when(repository.getVariableById(VARIABLE.getObservationVariableDbId())).thenReturn(VARIABLE);
 
         mockMvc.perform(get("/brapi/v1/variables/"+ VARIABLE.getObservationVariableDbId())
-            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+                            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id", is(VARIABLE.getUri())));
     }
@@ -67,8 +65,7 @@ class ObservationVariableControllerTest {
         ObservationVariableVO variable = new ObservationVariableVO();
         when(repository.getVariableById(identifier)).thenReturn(variable);
 
-        mockMvc.perform(get("/brapi/v1/variables/" + identifier)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/variables/" + identifier))
             .andExpect(status().isOk());
     }
 
@@ -76,8 +73,7 @@ class ObservationVariableControllerTest {
     void should_Return_Not_Found() throws Exception {
         when(repository.getVariableById("foo")).thenReturn(null);
 
-        mockMvc.perform(get("/brapi/v1/variables/foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/variables/foo"))
             .andExpect(status().isNotFound())
             .andExpect(jsonPath("$.metadata.status", hasSize(1)))
             .andExpect(jsonPath("$.metadata.status[0].code", is("404")));
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramControllerTest.java
index e609dc275e07f37db3a8748a3744a5f1f5b2924a..d05bb8a36085701feb5814a0dce3c84b812ab82a 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/ProgramControllerTest.java
@@ -43,8 +43,7 @@ class ProgramControllerTest {
     @Test
     void should_Not_Show_JSON_LD_Fields_By_Default() throws Exception {
         when(repository.getById(PROGRAM.getProgramDbId())).thenReturn(PROGRAM);
-        mockMvc.perform(get("/brapi/v1/programs/" + PROGRAM.getProgramDbId())
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/programs/" + PROGRAM.getProgramDbId()))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id").doesNotExist());
     }
@@ -54,8 +53,7 @@ class ProgramControllerTest {
         when(repository.getById(PROGRAM.getProgramDbId())).thenReturn(PROGRAM);
 
         mockMvc.perform(get("/brapi/v1/programs/"+ PROGRAM.getProgramDbId())
-            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+                            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id", is(PROGRAM.getUri())));
     }
@@ -67,8 +65,7 @@ class ProgramControllerTest {
         ProgramVO program = new ProgramVO();
         when(repository.getById(identifier)).thenReturn(program);
 
-        mockMvc.perform(get("/brapi/v1/programs/" + identifier)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/programs/" + identifier))
             .andExpect(status().isOk());
     }
 
@@ -76,8 +73,7 @@ class ProgramControllerTest {
     void should_Return_Not_Found() throws Exception {
         when(repository.getById("foo")).thenReturn(null);
 
-        mockMvc.perform(get("/brapi/v1/programs/foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/programs/foo"))
             .andExpect(status().isNotFound())
             .andExpect(jsonPath("$.metadata.status", hasSize(1)))
             .andExpect(jsonPath("$.metadata.status[0].code", is("404")));
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/StudyControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/StudyControllerTest.java
index d6acb3df6e4a86f8ddff5c1bafdd840c262c6764..253c4a0dca2cb03ee3ecc6765560c84decf52cdd 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/StudyControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/brapi/v1/StudyControllerTest.java
@@ -63,8 +63,7 @@ class StudyControllerTest {
     @Test
     void should_Not_Show_JSON_LD_Fields_By_Default() throws Exception {
         when(repository.getById(STUDY.getStudyDbId())).thenReturn(STUDY);
-        mockMvc.perform(get("/brapi/v1/studies/" + STUDY.getStudyDbId())
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/studies/" + STUDY.getStudyDbId()))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id").doesNotExist());
     }
@@ -74,8 +73,7 @@ class StudyControllerTest {
         when(repository.getById(STUDY.getStudyDbId())).thenReturn(STUDY);
 
         mockMvc.perform(get("/brapi/v1/studies/"+ STUDY.getStudyDbId())
-            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+                            .accept(BrapiJSONViewHandler.APPLICATION_LD_JSON))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.result.@id", is(STUDY.getUri())));
     }
@@ -87,8 +85,7 @@ class StudyControllerTest {
         StudyDetailVO study = new StudyDetailVO();
         when(repository.getById(identifier)).thenReturn(study);
 
-        mockMvc.perform(get("/brapi/v1/studies/" + identifier)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/studies/" + identifier))
             .andExpect(status().isOk());
     }
 
@@ -96,8 +93,7 @@ class StudyControllerTest {
     void should_Return_Not_Found() throws Exception {
         when(repository.getById("foo")).thenReturn(null);
 
-        mockMvc.perform(get("/brapi/v1/studies/foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/studies/foo"))
             .andExpect(status().isNotFound())
             .andExpect(jsonPath("$.metadata.status", hasSize(1)))
             .andExpect(jsonPath("$.metadata.status[0].code", is("404")));
@@ -113,8 +109,7 @@ class StudyControllerTest {
         PaginatedList<ObservationUnitVO> observationUnits = new PaginatedList<>(pagination, new ArrayList<>());
         when(observationUnitRepository.find(any())).thenReturn(observationUnits);
 
-        mockMvc.perform(get("/brapi/v1/studies/{id}/observationUnits?page={page}&pageSize={pageSize}", studyDbId, page, pageSize)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/studies/{id}/observationUnits?page={page}&pageSize={pageSize}", studyDbId, page, pageSize))
             .andExpect(jsonPath("$.metadata.pagination.currentPage", is(page)))
             .andExpect(jsonPath("$.metadata.pagination.pageSize", is(pageSize)));
     }
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmControllerTest.java
index ad6f539d096dddb194038ec133c9bb97688c0140..03edbd78f736b99ae574bb069a1238b24175d9ca 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/api/faidare/v1/GnpISGermplasmControllerTest.java
@@ -47,8 +47,7 @@ class GnpISGermplasmControllerTest {
         String id = "foo";
         when(service.getById(id)).thenReturn(null);
 
-        mockMvc.perform(get("/brapi/v1/germplasm?id=" + id)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm?id=" + id))
             .andExpect(status().isNotFound());
     }
 
@@ -57,8 +56,7 @@ class GnpISGermplasmControllerTest {
         when(service.find(any(GermplasmSearchCriteria.class))).thenReturn(null);
 
         String pui = "foo";
-        mockMvc.perform(get("/brapi/v1/germplasm?pui=" + pui)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/brapi/v1/germplasm?pui=" + pui))
             .andExpect(status().isNotFound());
     }
 
@@ -71,8 +69,7 @@ class GnpISGermplasmControllerTest {
         when(service.find(criteriaCaptor.capture())).thenReturn(germplasmPage);
 
         String pui = "doi:10.15454/1.4921786234137117E12";
-        mockMvc.perform(get("/faidare/v1/germplasm?pui=" + pui)
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/faidare/v1/germplasm?pui=" + pui))
             .andExpect(status().isOk());
 
         GermplasmSearchCriteria value = criteriaCaptor.getValue();
@@ -85,8 +82,7 @@ class GnpISGermplasmControllerTest {
 
     @Test
     void should_Return_Bad_Request_With_No_Param() throws Exception {
-        mockMvc.perform(get("/faidare/v1/germplasm")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
+        mockMvc.perform(get("/faidare/v1/germplasm"))
             .andExpect(status().isBadRequest());
     }
 
@@ -112,9 +108,7 @@ class GnpISGermplasmControllerTest {
 
         when(service.find(any(GermplasmSearchCriteria.class))).thenReturn(germplasmPage);
 
-        mockMvc.perform(get("/faidare/v1/germplasm?pui=foo")
-            .contentType(MediaType.APPLICATION_JSON_UTF8))
-
+        mockMvc.perform(get("/faidare/v1/germplasm?pui=foo"))
             // Should not have private fields
             .andExpect(jsonPath("$", not(hasProperty("groupId"))))
             .andExpect(jsonPath("$", not(hasProperty("speciesGroup"))))
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParserTest.java b/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParserTest.java
index ad44814021f823ad695e53feacf2a586860d9041..c215c6a81403124c3be7182741532bca017d9325 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParserTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/ESResponseParserTest.java
@@ -2,6 +2,7 @@ package fr.inra.urgi.faidare.elasticsearch;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import fr.inra.urgi.faidare.elasticsearch.fixture.DocumentObject;
+import org.apache.lucene.search.TotalHits;
 import org.assertj.core.util.Lists;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.common.bytes.BytesReference;
@@ -50,7 +51,7 @@ class ESResponseParserTest {
         float maxScore = 100;
 
         // Can't mock SearchHits since it is a final class
-        SearchHits hits = new SearchHits(hitsArray, expectedTotalHits, maxScore);
+        SearchHits hits = new SearchHits(hitsArray, new TotalHits(expectedTotalHits, TotalHits.Relation.EQUAL_TO), maxScore);
 
         SearchResponse response = mock(SearchResponse.class);
         when(response.getHits()).thenReturn(hits);
@@ -98,7 +99,7 @@ class ESResponseParserTest {
         SearchHit hit3 = mockSearchHit(object3);
 
         // Can't mock SearchHits since it is a final class
-        SearchHits hits = new SearchHits(new SearchHit[]{hit1, hit2, hit3}, 3, 100);
+        SearchHits hits = new SearchHits(new SearchHit[]{hit1, hit2, hit3}, new TotalHits(3L, TotalHits.Relation.EQUAL_TO), 100);
 
         SearchResponse response = mock(SearchResponse.class);
         when(response.getHits()).thenReturn(hits);
@@ -107,7 +108,7 @@ class ESResponseParserTest {
 
         assertThat(actualDocumentObject)
             .isNotNull().isNotEmpty()
-            .containsOnlyElementsOf(expectedDocumentObjects);
+            .hasSameElementsAs(expectedDocumentObjects);
     }
 
     private SearchHit mockSearchHit(DocumentObject object) throws IOException {
@@ -132,7 +133,7 @@ class ESResponseParserTest {
         assertThat(result).isNull();
 
         // Return null if no hits in hits
-        SearchHits hits = new SearchHits(null, 0, 100);
+        SearchHits hits = new SearchHits(null, new TotalHits(0, TotalHits.Relation.EQUAL_TO), 100);
         when(response.getHits()).thenReturn(hits);
 
         List<DocumentObject> result2 = parser.parseHits(response, DocumentObject.class);
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtilTest.java b/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtilTest.java
index b8a86407533fef5f21831fd31f01f753e8524f29..a712bfe44b6b5683c5c1f87a290e48d790136920 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtilTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/DocumentAnnotationUtilTest.java
@@ -50,6 +50,7 @@ class DocumentAnnotationUtilTest {
             .getDocumentObjectMetadata(ComplexDocument.class);
         assertThat(metadata).isNotNull();
         assertThat(metadata.getDocumentType()).isEqualTo("dataObject4");
+        assertThat(metadata.getIncludedFields()).containsExactly("id", "nested0");
         assertThat(metadata.getExcludedFields()).containsExactly("a", "b");
 
         assertThat(metadata.getIdField()).isEqualTo("@id");
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/fixture/ComplexDocument.java b/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/fixture/ComplexDocument.java
index dd9a2c789623a79ab4101136bdbd08e21fb82703..e799a70ab4fd8f21413735811c2bd058311f61f0 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/fixture/ComplexDocument.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/elasticsearch/document/fixture/ComplexDocument.java
@@ -11,7 +11,7 @@ import java.util.List;
 /**
  * @author gcornut
  */
-@Document(type = "dataObject4", excludedFields = {"a", "b"})
+@Document(type = "dataObject4", includedFields = { "id", "nested0"}, excludedFields = {"a", "b"})
 public class ComplexDocument {
     @Id(jsonName = "@id")
     String id;
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/filter/AngularRouteFilterTest.java b/backend/src/test/java/fr/inra/urgi/faidare/filter/AngularRouteFilterTest.java
deleted file mode 100644
index b71e9e39509201d931b6e469ff747524f7a4ddd4..0000000000000000000000000000000000000000
--- a/backend/src/test/java/fr/inra/urgi/faidare/filter/AngularRouteFilterTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package fr.inra.urgi.faidare.filter;
-
-import fr.inra.urgi.faidare.Application;
-import fr.inra.urgi.faidare.config.SecurityConfig;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.context.annotation.Import;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.test.util.ReflectionTestUtils;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import org.springframework.web.context.WebApplicationContext;
-
-import java.io.ByteArrayInputStream;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
-
-/**
- * Unit tests for {@link AngularRouteFilter}
- *
- * @author gcornut
- */
-@ExtendWith(SpringExtension.class)
-@Import(SecurityConfig.class)
-@SpringBootTest(classes = Application.class)
-class AngularRouteFilterTest {
-
-    @Autowired
-    private WebApplicationContext context;
-
-    @MockBean
-    private ResourceLoader resourceLoader;
-
-    private MockMvc mockMvc;
-
-    private AngularRouteFilter filter;
-
-    @BeforeEach
-    void setUp() {
-        filter = new AngularRouteFilter(resourceLoader);
-        mockMvc = MockMvcBuilders.webAppContextSetup(context)
-            .addFilter(filter, "/*")
-            .build();
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = {
-        // Static files
-        "/index.html",
-        "/script.js",
-        "/style.css",
-        "/image.gif",
-        "/icon.ico",
-        "/image.png",
-        "/image.jpg",
-        "/font.woff",
-        "/font.ttf",
-        // APIs
-        "/brapi/v1/studies",
-        "/faidare/v1/datadiscovery/suggest",
-        "/actuator/info",
-    })
-    void shouldNotForward(String url) throws Exception {
-        mockMvc.perform(get(url)).andExpect(forwardedUrl(null));
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = {
-        "/home",
-        "/studies/foo",
-        "/germplasm/bar",
-    })
-    void shouldForward(String url) throws Exception {
-        String indexBefore = "<html>\n" +
-            "  <base href=\"./\">\n" +
-            "</html>";
-        String indexAfter = "<html>\n" +
-            "  <base href=\"/gnpis-test/faidare/\">\n" +
-            "</html>";
-
-        ReflectionTestUtils.setField(filter, "serverContextPath", "/gnpis-test/faidare");
-
-        Resource mockResource = mock(Resource.class);
-        when(mockResource.getInputStream())
-            .thenReturn(new ByteArrayInputStream(indexBefore.getBytes()));
-        when(resourceLoader.getResource(anyString()))
-            .thenReturn(mockResource);
-
-        mockMvc.perform(get(url))
-            .andExpect(content().string(indexAfter));
-    }
-
-}
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/DataDiscoveryRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/DataDiscoveryRepositoryTest.java
index cf33ca07e1e9946e1d116bad061d79560f37a247..8d9d75556db6028cfddb4e72e3e6fdc9cb1f4155 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/DataDiscoveryRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/DataDiscoveryRepositoryTest.java
@@ -114,7 +114,7 @@ class DataDiscoveryRepositoryTest {
         criteria.setTypes(types);
         DataDiscoveryResponse result = repository.find(criteria);
         assertThat(result.getResult().getData()).isNotNull().hasSize(2)
-            .flatExtracting("type").containsOnlyElementsOf(types);
+            .flatExtracting("type").isSubsetOf(types);
     }
 
     @Test
@@ -124,7 +124,7 @@ class DataDiscoveryRepositoryTest {
         criteria.setSources(sources);
         DataDiscoveryResponse result = repository.find(criteria);
         assertThat(result.getResult().getData()).isNotNull().hasSize(2)
-            .extracting("sourceUri").containsOnlyElementsOf(sources);
+            .extracting("sourceUri").isSubsetOf(sources);
     }
 
     @Test
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmAttributeRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmAttributeRepositoryTest.java
index 9a7929b1874167a3b4aedd5a240f04d10532228e..af19b3c50396a576221d006bffe3e10b21770e1c 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmAttributeRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmAttributeRepositoryTest.java
@@ -101,6 +101,6 @@ class GermplasmAttributeRepositoryTest {
         assertThat(data).isNotNull().isNotEmpty().hasSize(2);
         assertThat(data)
             .extracting("attributeDbId")
-            .containsOnlyElementsOf(expectedAttributes);
+            .isSubsetOf(expectedAttributes);
     }
 }
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java
index 76285c6934b21838e2af8c7c9446aafde00787e5..4ba1d45b622eea6310e5e7bb99bc234201ace801 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/GermplasmRepositoryTest.java
@@ -6,12 +6,14 @@ import fr.inra.urgi.faidare.Application;
 import fr.inra.urgi.faidare.domain.criteria.GermplasmGETSearchCriteria;
 import fr.inra.urgi.faidare.domain.criteria.GermplasmPOSTSearchCriteria;
 import fr.inra.urgi.faidare.domain.criteria.GermplasmSearchCriteria;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.PedigreeVO;
 import fr.inra.urgi.faidare.domain.data.germplasm.ProgenyVO;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.domain.response.Pagination;
 import fr.inra.urgi.faidare.repository.es.setup.ESSetUp;
+import org.assertj.core.data.Index;
 import org.assertj.core.util.Lists;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
@@ -26,8 +28,10 @@ import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
 
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
@@ -49,7 +53,6 @@ class GermplasmRepositoryTest {
         esSetUp.initialize(ProgenyVO.class, 0L);
         esSetUp.initialize(PedigreeVO.class, 0L);
         esSetUp.initialize(GermplasmMcpdVO.class, 0L);
-
     }
 
     @Autowired
@@ -115,7 +118,7 @@ class GermplasmRepositoryTest {
     void should_Scroll_All() {
         GermplasmPOSTSearchCriteria criteria = new GermplasmPOSTSearchCriteria();
         Iterator<GermplasmVO> list = repository.scrollAll(criteria);
-        assertThat(list).isNotNull().hasSize(14);
+        assertThat(list).isNotNull().toIterable().hasSize(14);
     }
 
     @Test
@@ -123,9 +126,53 @@ class GermplasmRepositoryTest {
         GermplasmPOSTSearchCriteria criteria = new GermplasmPOSTSearchCriteria();
         criteria.setAccessionNumbers(Collections.singletonList("FOOOO"));
         Iterator<GermplasmVO> list = repository.scrollAll(criteria);
-        assertThat(list).isNotNull().hasSize(0);
+        assertThat(list).isNotNull().toIterable().hasSize(0);
+    }
+
+    @Test
+    void shouldScrollAllForSitemap() {
+        Iterator<GermplasmSitemapVO> list = repository.scrollAllForSitemap(100);
+        assertThat(list).toIterable()
+                        .isNotEmpty()
+                        .allMatch(vo -> !vo.getGermplasmDbId().isEmpty());
+    }
+
+    @Test
+    void shouldScrollGermplasmMcpdsByIds() {
+        Iterator<GermplasmMcpdVO> list = repository.scrollGermplasmMcpdsByIds(Collections.singleton("13705"), 1000);
+        assertThat(list).toIterable()
+                        .hasSize(1)
+                        .allMatch(vo -> !vo.getGermplasmDbId().isEmpty());
+
+        list = repository.scrollGermplasmMcpdsByIds(Collections.singleton("1370"), 1000);
+        assertThat(list).toIterable()
+                        .isEmpty();
+
+        list = repository.scrollGermplasmMcpdsByIds(Collections.singleton("Prunus"), 1000);
+        assertThat(list).toIterable()
+                        .isEmpty();
     }
 
+    @Test
+    void shouldScrollGermplasmsByIds() {
+        Iterator<GermplasmVO> list = repository.scrollGermplasmsByIds(
+            new HashSet<>(
+                Arrays.asList(
+                    "ZG9pOjEwLjE1NDU0LzEuNDkyMTc4NjM4MTc4MzY5NkUxMg==",
+                    "ZG9pOjEwLjE1NDU0LzEuNDkyMTc4NjM4NDcyNjA1MkUxMg==")
+            ), 1000);
+        assertThat(list).toIterable()
+                        .hasSize(2)
+                        .allMatch(vo -> !vo.getGermplasmDbId().isEmpty());
+
+        list = repository.scrollGermplasmsByIds(Collections.singleton("ZG9pOjEwL"), 1000);
+        assertThat(list).toIterable()
+                        .isEmpty();
+
+        list = repository.scrollGermplasmsByIds(Collections.singleton("ZG9pOjEwL"), 1000);
+        assertThat(list).toIterable()
+                        .isEmpty();
+    }
 
     @Test
     void should_Scroll_By_accessionNumber() {
@@ -135,8 +182,10 @@ class GermplasmRepositoryTest {
         criteria.setAccessionNumbers(Collections.singletonList(accessionNumber));
 
         Iterator<GermplasmVO> list = repository.scrollAll(criteria);
-        assertThat(list).isNotNull().hasSize(1)
-            .extracting("accessionNumber").containsOnly(accessionNumber);
+        assertThat(list).isNotNull()
+                        .toIterable()
+                        .hasSize(1)
+                        .extracting("accessionNumber").containsOnly(accessionNumber);
     }
 
     @Test
@@ -145,8 +194,10 @@ class GermplasmRepositoryTest {
         String accessionNumber = "2360";
         criteria.setAccessionNumbers(Collections.singletonList(accessionNumber));
         Iterator<GermplasmVO> list = repository.scrollAll(criteria);
-        assertThat(list).isNotNull().hasSize(1)
-            .extracting("accessionNumber").containsOnly(accessionNumber);
+        assertThat(list).isNotNull()
+                        .toIterable()
+                        .hasSize(1)
+                        .extracting("accessionNumber").containsOnly(accessionNumber);
     }
 
     @Test
@@ -155,7 +206,10 @@ class GermplasmRepositoryTest {
         String species = "vinifera";
         criteria.setGermplasmSpecies(Lists.newArrayList(species));
         Iterator<GermplasmVO> result = repository.scrollAll(criteria);
-        assertThat(result).isNotNull().isNotEmpty().extracting("species").containsOnly(species);
+        assertThat(result).isNotNull()
+                          .toIterable()
+                          .isNotEmpty()
+                          .extracting("species").containsOnly(species);
     }
 
     @Test
@@ -164,8 +218,10 @@ class GermplasmRepositoryTest {
         String genus = "Solanum";
         criteria.setGermplasmGenus(Lists.newArrayList(genus));
         Iterator<GermplasmVO> g = repository.scrollAll(criteria);
-        assertThat(g).isNotNull().hasSize(2)
-            .extracting("genus").containsOnly(genus);
+        assertThat(g).isNotNull()
+                     .toIterable()
+                     .hasSize(2)
+                     .extracting("genus").containsOnly(genus);
     }
 
     @Test
@@ -297,7 +353,7 @@ class GermplasmRepositoryTest {
         criteria.setGermplasmSpecies(Lists.newArrayList(species));
 
         Iterator<GermplasmVO> scroll = repository.scrollAll(criteria);
-        assertThat(scroll).isNotNull().hasSize(numberOfAestivum);
+        assertThat(scroll).isNotNull().toIterable().hasSize(numberOfAestivum);
 
         PaginatedList<GermplasmVO> pager = repository.find(criteria);
         assertThat(pager).isNotNull().isNotEmpty();
@@ -339,11 +395,11 @@ class GermplasmRepositoryTest {
         PaginatedList<GermplasmVO> vos = repository.find(criteria);
         assertThat(vos).isNotNull().isNotEmpty();
 
-        assertThat(vos).extracting("accessionNumber").containsOnlyElementsOf(accessionNumbers);
-        assertThat(vos).extracting("germplasmDbId").containsOnlyElementsOf(germplasmDbIds);
-        assertThat(vos).extracting("germplasmName").containsOnlyElementsOf(germplasmNames);
-        assertThat(vos).extracting("genus").containsOnlyElementsOf(germplasmGenus);
-        assertThat(vos).extracting("species").containsOnlyElementsOf(germplasmSpecies);
+        assertThat(vos).extracting("accessionNumber").isSubsetOf(accessionNumbers);
+        assertThat(vos).extracting("germplasmDbId").isSubsetOf(germplasmDbIds);
+        assertThat(vos).extracting("germplasmName").isSubsetOf(germplasmNames);
+        assertThat(vos).extracting("genus").isSubsetOf(germplasmGenus);
+        assertThat(vos).extracting("species").isSubsetOf(germplasmSpecies);
     }
 
     @Test
@@ -360,8 +416,8 @@ class GermplasmRepositoryTest {
         PaginatedList<GermplasmVO> vos = repository.find(criteria);
         assertThat(vos).isNotNull().isNotEmpty();
 
-        assertThat(vos).extracting("germplasmDbId").containsOnlyElementsOf(germplasmDbIds);
-        assertThat(vos).extracting("germplasmName").containsOnlyElementsOf(germplasmNames);
+        assertThat(vos).extracting("germplasmDbId").isSubsetOf(germplasmDbIds);
+        assertThat(vos).extracting("germplasmName").isSubsetOf(germplasmNames);
     }
 
     @Test
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryTest.java
index 88bcef7e6130cde2111f28f0e84ab70aae2a9e73..4bf6186663d41d17b821d39cb2b1181e001af180 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/LocationRepositoryTest.java
@@ -3,7 +3,9 @@ package fr.inra.urgi.faidare.repository.es;
 import com.google.common.collect.Sets;
 import fr.inra.urgi.faidare.Application;
 import fr.inra.urgi.faidare.domain.criteria.LocationCriteria;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
 import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.repository.es.setup.ESSetUp;
 import org.junit.jupiter.api.BeforeAll;
@@ -16,6 +18,7 @@ import org.springframework.context.annotation.Import;
 import org.springframework.test.context.TestPropertySource;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
+import java.util.Iterator;
 import java.util.Set;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -43,7 +46,7 @@ class LocationRepositoryTest {
         String expectedId = "805";
         LocationVO result = repository.getById(expectedId);
         assertThat(result).isNotNull();
-        assertThat(result).extracting("locationDbId").containsOnly(expectedId);
+        assertThat(result.getLocationDbId()).isEqualTo(expectedId);
     }
 
     @Test
@@ -112,6 +115,16 @@ class LocationRepositoryTest {
         PaginatedList<LocationVO> locations = repository.find(criteria);
 
         assertThat(locations).isNotNull().hasSize(3);
-        assertThat(locations).extracting("locationType").containsOnlyElementsOf(expectedTypes);
+        assertThat(locations).extracting("locationType").hasSameElementsAs(expectedTypes);
     }
+
+    @Test
+    void shouldScrollAllForSitemap() {
+        Iterator<LocationSitemapVO> list = repository.scrollAllForSitemap(100);
+        assertThat(list).toIterable()
+                        .isNotEmpty()
+                        .allMatch(vo -> !vo.getLocationDbId().isEmpty());
+    }
+
+
 }
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ObservationUnitRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ObservationUnitRepositoryTest.java
index 783b475780600f89a4821a4da74340f1735b07c6..e30c1f8f980fa2e0b5359ab6c4f1c38c7f0d9775 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ObservationUnitRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ObservationUnitRepositoryTest.java
@@ -132,7 +132,7 @@ class ObservationUnitRepositoryTest {
         assertThat(result)
             .flatExtracting("observations")
             .extracting("observationVariableDbId")
-            .containsOnlyElementsOf(variableIds);
+            .hasSameElementsAs(variableIds);
     }
 
     @Test
@@ -158,7 +158,7 @@ class ObservationUnitRepositoryTest {
         assertThat(result)
             .flatExtracting("observations")
             .extracting("observationVariableDbId")
-            .containsOnlyElementsOf(variableIds);
+            .hasSameElementsAs(variableIds);
 
         assertThat(result)
             .flatExtracting("observations")
@@ -220,7 +220,7 @@ class ObservationUnitRepositoryTest {
 
         assertThat(result)
             .extracting("studyDbId")
-            .containsOnlyElementsOf(studyIds);
+            .hasSameElementsAs(studyIds);
 
         assertThat(result)
             .extracting("observationLevel")
@@ -228,21 +228,21 @@ class ObservationUnitRepositoryTest {
 
         assertThat(result)
             .extracting("studyLocationDbId")
-            .containsOnlyElementsOf(locationIds);
+            .hasSameElementsAs(locationIds);
 
         assertThat(result)
             .extracting("germplasmDbId")
-            .containsOnlyElementsOf(germplasmIds);
+            .hasSameElementsAs(germplasmIds);
 
         assertThat(result)
             .flatExtracting("observations")
             .extracting("season")
-            .containsOnlyElementsOf(seasons);
+            .hasSameElementsAs(seasons);
 
         assertThat(result)
             .flatExtracting("observations")
             .extracting("observationVariableDbId")
-            .containsOnlyElementsOf(variableIds);
+            .hasSameElementsAs(variableIds);
 
         assertThat(result)
             .flatExtracting("observations")
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ProgramRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ProgramRepositoryTest.java
index ddc86daae6cc8c61751c854839880b7e4e48020a..252e412ecf85e226a43624ef5fa978f98c501913 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ProgramRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/ProgramRepositoryTest.java
@@ -40,7 +40,7 @@ class ProgramRepositoryTest {
         String expectedId = "P1";
         ProgramVO result = repository.getById(expectedId);
         assertThat(result).isNotNull();
-        assertThat(result).extracting("programDbId").containsOnly(expectedId);
+        assertThat(result.getProgramDbId()).isEqualTo(expectedId);
     }
 
     @Test
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryTest.java
index 42b2328714b627b7b2fc2099b3614257f61c7b49..af5cfa85677e4db56ff6bc973fabb6340f4a7629 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/StudyRepositoryTest.java
@@ -4,7 +4,9 @@ import com.google.common.collect.Sets;
 import fr.inra.urgi.faidare.Application;
 import fr.inra.urgi.faidare.domain.criteria.StudySearchCriteria;
 import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
 import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
+import fr.inra.urgi.faidare.domain.data.study.StudySitemapVO;
 import fr.inra.urgi.faidare.domain.data.study.StudySummaryVO;
 import fr.inra.urgi.faidare.domain.response.PaginatedList;
 import fr.inra.urgi.faidare.repository.es.setup.ESSetUp;
@@ -20,6 +22,7 @@ import org.springframework.test.context.TestPropertySource;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.Set;
 
 import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@@ -49,8 +52,8 @@ class StudyRepositoryTest {
         String expectedId = "BTH_Orgeval_2008_SetA2";
         StudyDetailVO result = repository.getById(expectedId);
         assertThat(result).isNotNull();
-        assertThat(result).extracting("studyDbId").containsOnly(expectedId);
-        assertThat(result).extracting("location").isNotEmpty();
+        assertThat(result.getStudyDbId()).isEqualTo(expectedId);
+        assertThat(result.getLocation()).isNotNull();
     }
 
 
@@ -93,7 +96,7 @@ class StudyRepositoryTest {
 
         assertThat(result).isNotNull().hasSize(3);
         assertThat(result).extracting("locationName")
-            .containsOnlyElementsOf(expectedLocations);
+            .hasSameElementsAs(expectedLocations);
     }
 
     @Test
@@ -106,7 +109,7 @@ class StudyRepositoryTest {
 
         assertThat(result).isNotNull().isNotEmpty();
         assertThat(result).extracting("name")
-            .containsOnlyElementsOf(expectedNames);
+            .hasSameElementsAs(expectedNames);
     }
 
     @Test
@@ -134,9 +137,9 @@ class StudyRepositoryTest {
         PaginatedList<StudySummaryVO> result = repository.find(criteria);
 
         assertThat(result).isNotNull().isNotEmpty();
-        assertThat(result).extracting("name").containsOnlyElementsOf(names);
-        assertThat(result).extracting("locationName").containsOnlyElementsOf(locations);
-        assertThat(result).extracting("programName").containsOnlyElementsOf(programs);
+        assertThat(result).extracting("name").hasSameElementsAs(names);
+        assertThat(result).extracting("locationName").hasSameElementsAs(locations);
+        assertThat(result).extracting("programName").hasSameElementsAs(programs);
         assertThat(result).extracting("active").containsOnly(active);
         assertThat(result).flatExtracting("seasons").contains(season);
         assertThat(result).extracting("studyType").containsOnly(type);
@@ -157,6 +160,14 @@ class StudyRepositoryTest {
         assertThat(result).extracting(sortField).isSortedAccordingTo(new DescendingOrder());
     }
 
+    @Test
+    void shouldScrollAllForSitemap() {
+        Iterator<StudySitemapVO> list = repository.scrollAllForSitemap(100);
+        assertThat(list).toIterable()
+                        .isNotEmpty()
+                        .allMatch(vo -> !vo.getStudyDbId().isEmpty());
+    }
+
     private class DescendingOrder implements Comparator<Object> {
         @Override
         public int compare(Object o1, Object o2) {
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/TrialRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/TrialRepositoryTest.java
index 1c7416b8e867f8a06e799c11ec1b47560214f328..660fa8abf376cfd73954b208fb196dab5fc12d8e 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/TrialRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/TrialRepositoryTest.java
@@ -42,7 +42,7 @@ class TrialRepositoryTest {
         String expectedId = "T1";
         TrialVO result = repository.getById(expectedId);
         assertThat(result).isNotNull();
-        assertThat(result).extracting("trialDbId").containsOnly(expectedId);
+        assertThat(result.getTrialDbId()).isEqualTo(expectedId);
     }
 
     @Test
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/XRefDocumentRepositoryTest.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/XRefDocumentRepositoryTest.java
index 8d488134985ba82d9197472b2b0a349873dd0343..f7ae93de08663973ab75a23410820fe8232d3998 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/XRefDocumentRepositoryTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/XRefDocumentRepositoryTest.java
@@ -62,12 +62,12 @@ class XRefDocumentRepositoryTest {
     @Test
     void should_Find_By_Linked_Id() {
         String id = "ID2";
-        List<String> linkedRessourcesID = Collections.singletonList(id);
+        List<String> linkedResourcesID = Collections.singletonList(id);
         XRefDocumentSearchCriteria criteria = new XRefDocumentSearchCriteria();
-        criteria.setLinkedRessourcesID(linkedRessourcesID);
+        criteria.setLinkedResourcesID(linkedResourcesID);
         PaginatedList<XRefDocumentVO> documents = repository.find(criteria);
         assertThat(documents).isNotNull().hasSize(2)
-            .flatExtracting("linkedRessourcesID")
+            .flatExtracting("linkedResourcesID")
                 .contains(id);
     }
 
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/setup/ESSetUp.java b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/setup/ESSetUp.java
index 235e03b61c1439246e811b7ba02355d4f2fe6cd7..760e5d3ff3c9caacdfc41e16730e9b139a093209 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/repository/es/setup/ESSetUp.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/repository/es/setup/ESSetUp.java
@@ -7,10 +7,7 @@ import fr.inra.urgi.faidare.config.FaidareProperties;
 import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
 import fr.inra.urgi.faidare.elasticsearch.document.DocumentAnnotationUtil;
 import fr.inra.urgi.faidare.repository.es.XRefDocumentRepositoryImpl;
-import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
-import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
-import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
 import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
 import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
 import org.elasticsearch.action.bulk.BulkRequest;
@@ -19,8 +16,12 @@ import org.elasticsearch.action.index.IndexRequest;
 import org.elasticsearch.action.support.master.AcknowledgedResponse;
 import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.client.indices.CreateIndexRequest;
+import org.elasticsearch.client.indices.CreateIndexResponse;
+import org.elasticsearch.client.indices.GetIndexRequest;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentType;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -47,8 +48,7 @@ public class ESSetUp {
      * Delete index/alias if it exists
      */
     private void deleteIndex(String indexName) throws IOException {
-        GetIndexRequest existsRequest = new GetIndexRequest();
-        existsRequest.indices(indexName);
+        GetIndexRequest existsRequest = new GetIndexRequest(indexName);
         boolean exists = client.indices().exists(existsRequest, RequestOptions.DEFAULT);
         if (!exists) {
             // Do not delete non existing index
@@ -76,11 +76,11 @@ public class ESSetUp {
 
         // with document mappings
         String mapping = readResource("./index/" + documentType + "_mapping.json");
-        createIndex.mapping(documentType, toXContentBuilder(mapping));
+        createIndex.mapping(mapping, XContentType.JSON);
 
         CreateIndexResponse createResponse = client.indices().create(createIndex, RequestOptions.DEFAULT);
         if (!createResponse.isAcknowledged()) {
-            throw new RuntimeException("Could not create index '" + indexName + "': " + createResponse.toString());
+            throw new RuntimeException("Could not create index '" + indexName + "': " + createResponse);
         }
 
         // Bulk index fixture data
@@ -93,7 +93,7 @@ public class ESSetUp {
         while (elements.hasNext()) {
             JsonNode document = elements.next();
 
-            IndexRequest indexRequest = new IndexRequest(indexName, documentType);
+            IndexRequest indexRequest = new IndexRequest(indexName);
             indexRequest.source(toXContentBuilder(document.toString()));
             bulkRequest.add(indexRequest);
         }
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/service/es/GermplasmServiceTest.java b/backend/src/test/java/fr/inra/urgi/faidare/service/es/GermplasmServiceTest.java
index 13e6e8e6385da0e074edeb1c3e6594c7ebb230e3..253abe39a3a10b7697338a32c5d02ad820e88f57 100644
--- a/backend/src/test/java/fr/inra/urgi/faidare/service/es/GermplasmServiceTest.java
+++ b/backend/src/test/java/fr/inra/urgi/faidare/service/es/GermplasmServiceTest.java
@@ -42,7 +42,7 @@ public class GermplasmServiceTest {
         File csvFile = germplasmService.exportCSV(criteria);
 
         CSVReader strings = new CSVReader(new FileReader(csvFile));
-        assertThat(strings.iterator()).hasSize(4);
+        assertThat(strings.iterator()).toIterable().hasSize(4);
         //TODO: Add more validation with mock data
     }
 
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/web/Fixtures.java b/backend/src/test/java/fr/inra/urgi/faidare/web/Fixtures.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b84aefb6f71f61fce51b201713969be15e50bff
--- /dev/null
+++ b/backend/src/test/java/fr/inra/urgi/faidare/web/Fixtures.java
@@ -0,0 +1,431 @@
+package fr.inra.urgi.faidare.web;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiAdditionalInfo;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiSibling;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiStudyDataLink;
+import fr.inra.urgi.faidare.domain.brapi.v1.data.BrapiTrialStudy;
+import fr.inra.urgi.faidare.domain.data.ContactVO;
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.TrialStudySummaryVO;
+import fr.inra.urgi.faidare.domain.data.TrialVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.CollPopVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.DonorVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GenealogyVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmAttributeValueListVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmAttributeValueVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmInstituteVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.InstituteVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.PedigreeVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.PhotoVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.PuiNameValueVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.SiblingVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.SiteVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.TaxonSourceVO;
+import fr.inra.urgi.faidare.domain.data.study.StudyDataLinkVO;
+import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
+import fr.inra.urgi.faidare.domain.data.variable.ObservationVariableVO;
+import fr.inra.urgi.faidare.domain.data.variable.TraitVO;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSourceImpl;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+
+/**
+ * Utility class to create test fixtures
+ * @author JB Nizet
+ */
+public class Fixtures {
+    public static LocationVO createSite() {
+        LocationVO site = new LocationVO();
+        site.setLocationDbId("france");
+        site.setLocationName("France");
+        site.setSourceUri("https://urgi.versailles.inrae.fr/gnpis");
+        site.setUri("Test URI");
+        site.setUrl("https://google.com");
+        site.setLatitude(45.65);
+        site.setLongitude(1.34);
+        BrapiAdditionalInfo additionalInfo = new BrapiAdditionalInfo();
+        additionalInfo.addProperty("Slope", 4.32);
+        additionalInfo.addProperty("Distance to city", "3 km");
+        additionalInfo.addProperty("foo", "bar");
+        additionalInfo.addProperty("baz", "zing");
+        additionalInfo.addProperty("blob", null);
+        site.setAdditionalInfo(additionalInfo);
+        return site;
+    }
+
+    public static XRefDocumentVO createXref(String name) {
+        XRefDocumentVO xref = new XRefDocumentVO();
+        xref.setName(name);
+        xref.setDescription("A very large description for the xref " + name + " which has way more than 120 characters bla bla bla bla bla bla bla bla bla bla bla bla");
+        xref.setDatabaseName("db_" + name);
+        xref.setUrl("https://google.com");
+        xref.setEntryType("type " + name);
+        return xref;
+    }
+
+    public static DataSource createDataSource() {
+        DataSourceImpl dataSource = new DataSourceImpl();
+        dataSource.setUri("Test URI");
+        dataSource.setUrl("https://google.fr");
+        dataSource.setName("Some Data Source");
+        dataSource.setIdentifier("DS1");
+        dataSource.setImage("https://images.com/image.png");
+        return dataSource;
+    }
+
+    public static StudyDetailVO createStudy() {
+        StudyDetailVO study = new StudyDetailVO();
+        study.setStudyDbId("study1");
+        study.setUri("Test URI");
+        study.setStudyName("Study 1");
+        study.setStudyType("Doability");
+        study.setProgramName("Program 1");
+        study.setActive(true);
+        study.setStartDate(new Date());
+        study.setDataLinks(Arrays.asList(createDataLink()));
+        study.setContacts(Arrays.asList(createContact()));
+
+        BrapiAdditionalInfo additionalInfo = new BrapiAdditionalInfo();
+        additionalInfo.addProperty("foo", "bar");
+        additionalInfo.addProperty("baz", "zing");
+        additionalInfo.addProperty("blob", null);
+        study.setAdditionalInfo(additionalInfo);
+
+        study.setLocationDbId("france");
+        study.setLocationName("France");
+        study.setGermplasmDbIds(Collections.singleton("germplasm1"));
+        study.setTrialDbIds(Collections.singleton("trial1"));
+        return study;
+    }
+
+    private static ContactVO createContact() {
+        ContactVO contact = new ContactVO();
+        contact.setType("Pro");
+        contact.setName("John Doe");
+        contact.setEmail("john@doe.com");
+        contact.setInstituteName("UCLA");
+        return contact;
+    }
+
+    private static BrapiStudyDataLink createDataLink() {
+        StudyDataLinkVO dataLink = new StudyDataLinkVO();
+        dataLink.setName("Link 1");
+        dataLink.setUrl("http://inrae.fr");
+        return dataLink;
+    }
+
+    public static HtmlContentResultMatchers htmlContent() {
+        return new HtmlContentResultMatchers();
+    }
+
+    public static GermplasmVO createGermplasm() {
+        GermplasmVO germplasm = new GermplasmVO();
+
+        germplasm.setGermplasmDbId("germplasm1");
+        germplasm.setGermplasmName("BLE BARBU DU ROUSSILLON");
+        germplasm.setAccessionNumber("1408");
+        germplasm.setSynonyms(Arrays.asList("BLE DU ROUSSILLON", "FRA051:1699", "ROUSSILLON"));
+        PhotoVO photo = new PhotoVO();
+        photo.setPhotoName("Blé du roussillon");
+        photo.setCopyright("INRA, Emmanuelle BOULAT/Lionel BARDY 2012");
+        photo.setThumbnailFile("https://urgi.versailles.inrae.fr/files/siregal/images/accession/CEREALS/thumbnails/thumb_1408_R09_S.jpg");
+        photo.setFile("https://urgi.versailles.inrae.fr/files/siregal/images/accession/CEREALS/1408_R09_S.jpg");
+        germplasm.setPhoto(photo);
+
+        InstituteVO holdingGenBank = new InstituteVO();
+        holdingGenBank.setLogo("https://urgi.versailles.inra.fr/files/siregal/images/grc/inra_brc_en.png");
+        holdingGenBank.setInstituteName("INRA BRC");
+        holdingGenBank.setWebSite("http://google.fr");
+        germplasm.setHoldingGenbank(holdingGenBank);
+
+        germplasm.setBiologicalStatusOfAccessionCode("Traditional cultivar/landrace ");
+        germplasm.setPedigree("LV");
+        SiteVO originSite = new SiteVO();
+        originSite.setSiteId("1234");
+        originSite.setSiteName("Le Moulon");
+        originSite.setSiteType("Origin site");
+        originSite.setLatitude(47.0F);
+        originSite.setLongitude(12.0F);
+        germplasm.setOriginSite(originSite);
+
+        List<SiteVO> evaluationSites = new ArrayList<>();
+        for (int i = 0; i < 5; i++) {
+            SiteVO evaluationSite = new SiteVO();
+            evaluationSite.setSiteId(Integer.toString(12347 + i));
+            evaluationSite.setSiteType("Evaluation site");
+            evaluationSite.setSiteName("Site " + i);
+            evaluationSite.setLatitude(46.0F + i);
+            evaluationSite.setLongitude(13.0F + i);
+            evaluationSites.add(evaluationSite);
+        }
+        germplasm.setEvaluationSites(evaluationSites);
+
+        germplasm.setGenus("Genus 1");
+        germplasm.setSpecies("Species 1");
+        germplasm.setSpeciesAuthority("Species Auth");
+        germplasm.setSourceUri("https://urgi.versailles.inrae.fr/gnpis");
+        germplasm.setSubtaxa("Subtaxa 1");
+        germplasm.setGenusSpeciesSubtaxa("Triticum aestivum subsp. aestivum");
+        germplasm.setSubtaxaAuthority("INRAE");
+        germplasm.setTaxonIds(Arrays.asList(createTaxonId(), createTaxonId()));
+        germplasm.setTaxonComment("C'est bon le blé");
+        germplasm.setTaxonCommonNames(Arrays.asList("Blé tendre", "Bread wheat", "Soft wheat"));
+        germplasm.setTaxonSynonyms(Arrays.asList("Blé tendre1", "Bread wheat1", "Soft wheat1"));
+
+        InstituteVO holdingInstitute = new InstituteVO();
+        holdingInstitute.setInstituteName("GDEC - UMR Génétique, Diversité et Ecophysiologie des Céréales");
+        holdingInstitute.setLogo("https://urgi.versailles.inra.fr/files/siregal/images/grc/inra_brc_en.png");
+        holdingInstitute.setWebSite("https://google.fr/q=qsdqsdqsdslqlsdnqlsdqlsdlqskdlqdqlsdqsdqsdqd");
+        holdingInstitute.setInstituteCode("GDEC");
+        holdingInstitute.setInstituteType("Type1");
+        holdingInstitute.setAcronym("G.D.E.C");
+        holdingInstitute.setAddress("Lyon");
+        holdingInstitute.setOrganisation("SAS");
+        germplasm.setHoldingInstitute(holdingInstitute);
+
+        germplasm.setPresenceStatus("Maintained");
+
+        GermplasmInstituteVO collector = new GermplasmInstituteVO();
+        collector.setMaterialType("Fork");
+        collector.setCollectors("Joe, Jack, William, Averell");
+        InstituteVO collectingInstitute = new InstituteVO();
+        collectingInstitute.setInstituteName("Ninja Squad");
+        collector.setInstitute(collectingInstitute);
+        collector.setAccessionNumber("567");
+        germplasm.setCollector(collector);
+
+        SiteVO collectingSite = new SiteVO();
+        collectingSite.setSiteId("1235");
+        collectingSite.setSiteName("St Just");
+        collectingSite.setSiteType("Collecting site");
+        collectingSite.setLatitude(48.0F);
+        collectingSite.setLongitude(13.0F);
+        germplasm.setCollectingSite(collectingSite);
+        germplasm.setAcquisitionDate("In the summer");
+
+        GermplasmInstituteVO breeder = new GermplasmInstituteVO();
+        InstituteVO breedingInstitute = new InstituteVO();
+        breedingInstitute.setInstituteName("Microsoft");
+        breeder.setInstitute(breedingInstitute);
+        breeder.setAccessionCreationDate(2015);
+        breeder.setAccessionNumber("678");
+        breeder.setRegistrationYear(2016);
+        breeder.setDeregistrationYear(2019);
+        germplasm.setBreeder(breeder);
+
+        germplasm.setDonors(Arrays.asList(
+            createDonor()
+        ));
+
+        germplasm.setDistributors(Arrays.asList(
+            createDistributor()
+        ));
+
+        germplasm.setChildren(Arrays.asList(createChild(), createChild()));
+
+        germplasm.setGermplasmPUI("germplasmPUI");
+        germplasm.setPopulation(Arrays.asList(createPopulation1(), createPopulation2(), createPopulation3()));
+
+        germplasm.setCollection(Arrays.asList(createCollection()));
+
+        germplasm.setPanel(Arrays.asList(createPanel()));
+
+        return germplasm;
+    }
+
+    public static GermplasmVO createGermplasmMinimal() {
+        GermplasmVO germplasm = new GermplasmVO();
+
+        germplasm.setGermplasmDbId("germplasm-mini1");
+        germplasm.setGermplasmName("BLE BARBU DU ROUSSILLON mini");
+        germplasm.setAccessionNumber("1408-mini");
+
+        InstituteVO holdingGenBank = new InstituteVO();
+        holdingGenBank.setLogo("https://urgi.versailles.inra.fr/files/siregal/images/grc/inra_brc_en.png");
+        holdingGenBank.setInstituteName("INRA BRC");
+        holdingGenBank.setWebSite("http://google.fr");
+        germplasm.setHoldingGenbank(holdingGenBank);
+
+        germplasm.setBiologicalStatusOfAccessionCode("Traditional cultivar/landrace ");
+
+
+        germplasm.setGenus("Genus 1");
+        germplasm.setSpecies("Species 1");
+        germplasm.setTaxonIds(Arrays.asList(createTaxonId(), createTaxonId()));
+
+        InstituteVO holdingInstitute = new InstituteVO();
+        holdingInstitute.setInstituteName("GDEC - UMR Génétique, Diversité et Ecophysiologie des Céréales");
+        holdingInstitute.setInstituteCode("GDEC");
+        holdingInstitute.setInstituteType("Type1");
+        holdingInstitute.setAcronym("G.D.E.C");
+        holdingInstitute.setOrganisation("SAS");
+        germplasm.setHoldingInstitute(holdingInstitute);
+
+        germplasm.setPresenceStatus("Maintained");
+
+        germplasm.setGermplasmPUI("germplasmPUI mini");
+
+        return germplasm;
+    }
+
+
+    private static DonorVO createDonor() {
+        DonorVO result = new DonorVO();
+        result.setDonorGermplasmPUI("PUI1");
+        result.setDonationDate(2017);
+        result.setDonorAccessionNumber("3456");
+        result.setDonorInstituteCode("GD46U");
+        InstituteVO institute = new InstituteVO();
+        institute.setInstituteName("Hello");
+        result.setDonorInstitute(institute);
+        return result;
+    }
+
+    private static GermplasmInstituteVO createDistributor() {
+        GermplasmInstituteVO result = new GermplasmInstituteVO();
+        InstituteVO institute = new InstituteVO();
+        institute.setInstituteName("Microsoft");
+        result.setInstitute(institute);
+        result.setAccessionNumber("678");
+        result.setDistributionStatus("OK");
+        return result;
+    }
+
+    private static PedigreeVO createPedigree() {
+        PedigreeVO result = new PedigreeVO();
+        result.setPedigree("Pedigree 1");
+        result.setParent1DbId("12345");
+        result.setParent1Name("Parent 1");
+        result.setParent1Type("P1");
+        result.setParent2DbId("12346");
+        result.setParent2Name("Parent 2");
+        result.setParent2Type("P2");
+        result.setCrossingPlan("crossing plan 1");
+        result.setCrossingYear("2012");
+        result.setSiblings(Arrays.asList(createBrapiSibling()));
+        return result;
+    }
+
+    private static BrapiSibling createBrapiSibling() {
+        SiblingVO sibling = new SiblingVO();
+        sibling.setGermplasmDbId("5678");
+        sibling.setDefaultDisplayName("Sibling 5678");
+        return sibling;
+    }
+
+    private static GenealogyVO createChild() {
+        GenealogyVO result = new GenealogyVO();
+        result.setFirstParentName("CP1");
+        result.setSecondParentName("CP2");
+        result.setSibblings(Arrays.asList(createPuiNameValueVO(), createPuiNameValueVO()));
+        return result;
+    }
+
+    private static PuiNameValueVO createPuiNameValueVO() {
+        PuiNameValueVO result = new PuiNameValueVO();
+        result.setName("Child 1");
+        result.setPui("pui1");
+        return result;
+    }
+
+    private static CollPopVO createPopulation1() {
+        CollPopVO result = new CollPopVO();
+        result.setName("Population 1");
+        result.setType("Pop Type 1");
+        result.setGermplasmCount(3);
+        result.setGermplasmRef(createPuiNameValueVO());
+        return result;
+    }
+
+    private static CollPopVO createPopulation2() {
+        CollPopVO result = new CollPopVO();
+        result.setName("Population 2");
+        result.setGermplasmCount(3);
+        PuiNameValueVO puiNameValueVO = createPuiNameValueVO();
+        puiNameValueVO.setPui("germplasmPUI");
+        result.setGermplasmRef(puiNameValueVO);
+        return result;
+    }
+
+    private static CollPopVO createPopulation3() {
+        CollPopVO result = new CollPopVO();
+        result.setName("Population 3");
+        result.setGermplasmCount(5);
+        return result;
+    }
+
+    private static CollPopVO createCollection() {
+        CollPopVO result = new CollPopVO();
+        result.setName("Collection 1");
+        result.setGermplasmCount(7);
+        return result;
+    }
+
+    private static CollPopVO createPanel() {
+        CollPopVO result = new CollPopVO();
+        result.setName("The_panel_1");
+        result.setGermplasmCount(2);
+        return result;
+    }
+
+    private static TaxonSourceVO createTaxonId() {
+        TaxonSourceVO result = new TaxonSourceVO();
+        result.setTaxonId("taxon1");
+        result.setSourceName("ThePlantList");
+        return result;
+    }
+
+    public static TrialVO createTrial() {
+        TrialVO trial = new TrialVO();
+        trial.setTrialName("Trail 1");
+        trial.setTrialType("Trial type 1");
+        trial.setDocumentationURL("http://trials.com");
+        trial.setStudies(Arrays.asList(createTrialStudy()));
+        return trial;
+    }
+
+    private static BrapiTrialStudy createTrialStudy() {
+        TrialStudySummaryVO study = new TrialStudySummaryVO();
+        study.setStudyDbId("study2");
+        study.setStudyName("Study 2");
+        return study;
+    }
+
+    public static GermplasmAttributeValueListVO createGermplasmAttributeValueList() {
+        GermplasmAttributeValueVO value = new GermplasmAttributeValueVO();
+        value.setAttributeName("A1");
+        value.setValue("V1");
+
+        GermplasmAttributeValueListVO list = new GermplasmAttributeValueListVO();
+        list.setData(Arrays.asList(value));
+        return list;
+    }
+
+    public static ObservationVariableVO createVariable() {
+        ObservationVariableVO variable = new ObservationVariableVO();
+        variable.setObservationVariableDbId("variable1");
+        variable.setDocumentationURL("http://variables.com");
+        variable.setName("Variable 1");
+        variable.setSynonyms(Arrays.asList("V1"));
+        variable.setOntologyName("Ontology 1");
+        TraitVO trait = new TraitVO();
+        trait.setDescription("Trait 1");
+        variable.setTrait(trait);
+        return variable;
+    }
+
+    public static GermplasmMcpdVO createGermplasmMcpd() {
+        GermplasmMcpdVO result = new GermplasmMcpdVO();
+        result.setGermplasmPUI("PUI1");
+        result.setInstituteCode("Inst1");
+        return result;
+    }
+}
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/web/HtmlContentResultMatchers.java b/backend/src/test/java/fr/inra/urgi/faidare/web/HtmlContentResultMatchers.java
new file mode 100644
index 0000000000000000000000000000000000000000..74e7234e4f4915e9ca343486bb0a12179ae36520
--- /dev/null
+++ b/backend/src/test/java/fr/inra/urgi/faidare/web/HtmlContentResultMatchers.java
@@ -0,0 +1,44 @@
+package fr.inra.urgi.faidare.web;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.springframework.test.web.servlet.ResultMatcher;
+
+/**
+ * Result matchers useful to perform various checks on HTML content
+ * @author JB Nizet
+ */
+public class HtmlContentResultMatchers {
+    public ResultMatcher endsCorrectly() {
+        return result -> {
+            assertThat(result.getResponse().getContentAsString().trim()).endsWith("</html>");
+        };
+    }
+
+    public ResultMatcher hasTitle(String title) {
+        return result -> {
+            Document document = Jsoup.parse(result.getResponse().getContentAsString());
+            assertThat(document.title().trim()).isEqualTo(title);
+        };
+    }
+
+    public ResultMatcher containsH2s(String... h2Texts) {
+        return result -> {
+            Document document = Jsoup.parse(result.getResponse().getContentAsString());
+            Set<String> actualH2Texts = document.getElementsByTag("h2")
+                                     .stream()
+                                     .map(element -> element.text().trim())
+                                     .collect(
+                                         Collectors.toSet());
+            for (String h2Text : h2Texts) {
+                assertThat(actualH2Texts).contains(h2Text);
+            }
+        };
+    }
+}
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/web/germplasm/GermplasmControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/web/germplasm/GermplasmControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c089b0f512ba5c59dda74b7651f3efc03c99979e
--- /dev/null
+++ b/backend/src/test/java/fr/inra/urgi/faidare/web/germplasm/GermplasmControllerTest.java
@@ -0,0 +1,296 @@
+package fr.inra.urgi.faidare.web.germplasm;
+
+import static fr.inra.urgi.faidare.web.Fixtures.htmlContent;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Sets;
+import fr.inra.urgi.faidare.config.FaidareProperties;
+import fr.inra.urgi.faidare.domain.criteria.GermplasmGETSearchCriteria;
+import fr.inra.urgi.faidare.domain.criteria.GermplasmSearchCriteria;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmAttributeValueListVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmMcpdVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmSitemapVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
+import fr.inra.urgi.faidare.domain.response.PaginatedList;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.repository.es.GermplasmAttributeRepository;
+import fr.inra.urgi.faidare.repository.es.GermplasmRepository;
+import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
+import fr.inra.urgi.faidare.web.Fixtures;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatcher;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+
+/**
+ * MVC tests for {@link GermplasmController}
+ * @author JB Nizet
+ */
+@WebMvcTest(GermplasmController.class)
+@Import({GermplasmMcpdExportService.class, GermplasmExportService.class})
+public class GermplasmControllerTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @MockBean
+    private GermplasmRepository mockGermplasmRepository;
+
+    @MockBean
+    private FaidareProperties mockFaidareProperties;
+
+    @MockBean
+    private XRefDocumentRepository mockXRefDocumentRepository;
+
+    @MockBean
+    private GermplasmAttributeRepository mockGermplasmAttributeRepository;
+
+    private GermplasmVO germplasm;
+    private List<XRefDocumentVO> crossReferences;
+    private DataSource dataSource;
+
+    @BeforeEach
+    void prepare() {
+        germplasm = Fixtures.createGermplasm();
+        when(mockGermplasmRepository.getById(germplasm.getGermplasmDbId())).thenReturn(germplasm);
+
+        crossReferences = Arrays.asList(
+            Fixtures.createXref("foobar"),
+            Fixtures.createXref("bazbing")
+        );
+        when(mockXRefDocumentRepository.find(any()))
+            .thenReturn(new PaginatedList<>(null, crossReferences));
+
+        dataSource = Fixtures.createDataSource();
+        when(mockFaidareProperties.getByUri(germplasm.getSourceUri())).thenReturn(dataSource);
+
+        List<GermplasmAttributeValueListVO> attributes = Arrays.asList(Fixtures.createGermplasmAttributeValueList());
+        when(mockGermplasmAttributeRepository.find(any())).thenReturn(new PaginatedList<>(null, attributes));
+    }
+
+    @Test
+    void shouldDisplayGermplasm() throws Exception {
+        mockMvc.perform(get("/germplasms/{id}", germplasm.getGermplasmDbId()))
+               .andExpect(status().isOk())
+               .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+               .andExpect(htmlContent().hasTitle("Germplasm: BLE BARBU DU ROUSSILLON"))
+               .andExpect(htmlContent().containsH2s("Identification",
+                                                    "Depositary",
+                                                    "Collector",
+                                                    "Breeder",
+                                                    "Donors",
+                                                    "Distributors",
+                                                    "Evaluation Data",
+                                                    "Genealogy",
+                                                    "Population",
+                                                    "Collection",
+                                                    "Panel",
+                                                    "Cross references"))
+               .andExpect(htmlContent().endsCorrectly());
+    }
+
+    @Test
+    void shouldDisplayGermplasmWithNullCollector() throws Exception {
+        germplasm.setCollector(null);
+
+        mockMvc.perform(get("/germplasms/{id}", germplasm.getGermplasmDbId()))
+               .andExpect(status().isOk())
+               .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+               .andExpect(htmlContent().hasTitle("Germplasm: BLE BARBU DU ROUSSILLON"))
+               .andExpect(htmlContent().containsH2s("Identification",
+                                                    "Depositary",
+                                                    "Collector",
+                                                    "Breeder",
+                                                    "Donors",
+                                                    "Distributors",
+                                                    "Evaluation Data",
+                                                    "Genealogy",
+                                                    "Population",
+                                                    "Collection",
+                                                    "Panel",
+                                                    "Cross references"))
+               .andExpect(htmlContent().endsCorrectly());
+    }
+
+    @Test
+    void shouldDisplayGermplasmWithIdAsParameter() throws Exception {
+        mockMvc.perform(get("/germplasms").param("id", germplasm.getGermplasmDbId()))
+               .andExpect(status().isOk())
+               .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+               .andExpect(htmlContent().hasTitle("Germplasm: BLE BARBU DU ROUSSILLON"))
+               .andExpect(htmlContent().containsH2s("Identification",
+                                                    "Depositary",
+                                                    "Collector",
+                                                    "Breeder",
+                                                    "Donors",
+                                                    "Distributors",
+                                                    "Evaluation Data",
+                                                    "Genealogy",
+                                                    "Population",
+                                                    "Collection",
+                                                    "Panel",
+                                                    "Cross references"))
+               .andExpect(htmlContent().endsCorrectly());
+    }
+
+    @Test
+    void shouldDisplayGermplasmWithPuiAsParameter() throws Exception {
+        PaginatedList<GermplasmVO> puiList = new PaginatedList<>(null, Collections.singletonList(germplasm));
+        when(mockGermplasmRepository.find(any())).thenReturn(puiList);
+
+        mockMvc.perform(get("/germplasms").param("pui", germplasm.getGermplasmPUI()))
+               .andExpect(status().isOk())
+               .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+               .andExpect(htmlContent().hasTitle("Germplasm: BLE BARBU DU ROUSSILLON"))
+               .andExpect(htmlContent().containsH2s("Identification",
+                                                    "Depositary",
+                                                    "Collector",
+                                                    "Breeder",
+                                                    "Donors",
+                                                    "Distributors",
+                                                    "Evaluation Data",
+                                                    "Genealogy",
+                                                    "Population",
+                                                    "Collection",
+                                                    "Panel",
+                                                    "Cross references"))
+               .andExpect(htmlContent().endsCorrectly());
+
+        ArgumentMatcher<GermplasmSearchCriteria> criteriaMatcher = criteria ->
+            criteria instanceof GermplasmGETSearchCriteria
+                && ((GermplasmGETSearchCriteria) criteria).getGermplasmPUI()
+                                                          .equals(Collections.singletonList(germplasm.getGermplasmPUI()));
+        verify(mockGermplasmRepository).find(argThat(criteriaMatcher));
+    }
+
+    @Test
+    void shouldSupportLegacyPath() throws Exception {
+        PaginatedList<GermplasmVO> puiList = new PaginatedList<>(null, Collections.singletonList(germplasm));
+        when(mockGermplasmRepository.find(any())).thenReturn(puiList);
+
+        mockMvc.perform(get("/germplasm").param("pui", germplasm.getGermplasmPUI()))
+               .andExpect(status().isOk())
+               .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+               .andExpect(htmlContent().hasTitle("Germplasm: BLE BARBU DU ROUSSILLON"))
+               .andExpect(htmlContent().endsCorrectly());
+    }
+
+    @Test
+    void shouldGenerateSitemap() throws Exception {
+        List<GermplasmSitemapVO> germplasms = Arrays.asList(
+            new GermplasmSitemapVO("germplasm1"),
+            new GermplasmSitemapVO("germplasm4"),
+            new GermplasmSitemapVO("germplasm45"),
+            new GermplasmSitemapVO("germplasm73")
+        );
+
+        // the hashCode algorithm is specified in the javadoc, so it's guaranteed to be
+        // the same everywhere
+        // uncomment the following line to see which sitemap index each study has
+        // germplasms.forEach(germplasm -> System.out.println(germplasm.getGermplasmDbId() + " = " + Math.floorMod(germplasm.getGermplasmDbId().hashCode(), Sitemaps.BUCKET_COUNT)));
+
+        when(mockGermplasmRepository.scrollAllForSitemap(anyInt())).thenAnswer(invocation -> germplasms.iterator());
+
+        testSitemap(6, "http://localhost/faidare/germplasms/germplasm1\nhttp://localhost/faidare/germplasms/germplasm45\n");
+        testSitemap(9, "http://localhost/faidare/germplasms/germplasm4\nhttp://localhost/faidare/germplasms/germplasm73\n");
+        testSitemap(7, "");
+
+        mockMvc.perform(get("/faidare/germplasms/sitemap-17.txt")
+                            .contextPath("/faidare"))
+               .andExpect(status().isNotFound());
+    }
+
+    @Test
+    void shouldExportMcpds() throws Exception {
+        List<GermplasmMcpdVO> germplasms = Arrays.asList(
+            Fixtures.createGermplasmMcpd(),
+            Fixtures.createGermplasmMcpd()
+        );
+
+        GermplasmMcpdExportCommand command = new GermplasmMcpdExportCommand(
+            Sets.newHashSet("g1", "g2"),
+            Arrays.asList(GermplasmMcpdExportableField.PUID, GermplasmMcpdExportableField.INSTCODE));
+
+        when(mockGermplasmRepository.scrollGermplasmMcpdsByIds(eq(command.getIds()), anyInt()))
+            .thenAnswer(invocation -> germplasms.iterator());
+
+        MvcResult mvcResult = mockMvc.perform(post("/germplasms/exports/mcpd")
+                                                  .contentType(MediaType.APPLICATION_JSON)
+                                                  .content(objectMapper.writeValueAsBytes(
+                                                      command)))
+                                     .andExpect(request().asyncStarted())
+                                     .andReturn();
+
+        this.mockMvc.perform(asyncDispatch(mvcResult))
+               .andExpect(status().isOk())
+               .andExpect(content().contentType("text/csv"))
+               .andExpect(content().string("\"PUID\";\"INSTCODE\"\n" +
+                                               "\"PUI1\";\"Inst1\"\n" +
+                                               "\"PUI1\";\"Inst1\"\n"));
+    }
+
+    @Test
+    void shouldExportPlantMaterials() throws Exception {
+        List<GermplasmVO> germplasms = Arrays.asList(
+            Fixtures.createGermplasm(),
+            Fixtures.createGermplasm(),
+            Fixtures.createGermplasmMinimal()
+        );
+
+        GermplasmExportCommand command = new GermplasmExportCommand(
+            Sets.newHashSet("g1", "g2"),
+            Arrays.asList(GermplasmExportableField.DOI,
+                          GermplasmExportableField.ACCESSION_NUMBER,
+                          GermplasmExportableField.ACCESSION_NAME));
+
+        when(mockGermplasmRepository.scrollGermplasmsByIds(eq(command.getIds()), anyInt()))
+            .thenAnswer(invocation -> germplasms.iterator());
+
+        MvcResult mvcResult = mockMvc.perform(post("/germplasms/exports/plant-material")
+                                                  .contentType(MediaType.APPLICATION_JSON)
+                                                  .content(objectMapper.writeValueAsBytes(
+                                                      command)))
+                                     .andExpect(request().asyncStarted())
+                                     .andReturn();
+
+        this.mockMvc.perform(asyncDispatch(mvcResult))
+                    .andExpect(status().isOk())
+                    .andExpect(content().contentType("text/csv"))
+                    .andExpect(content().string("\"DOI\";\"Accession number\";\"Accession name\"\n" +
+                                                    "\"germplasmPUI\";\"1408\";\"BLE BARBU DU ROUSSILLON\"\n" +
+                                                    "\"germplasmPUI\";\"1408\";\"BLE BARBU DU ROUSSILLON\"\n" +
+                                                    "\"germplasmPUI mini\";\"1408-mini\";\"BLE BARBU DU ROUSSILLON mini\"\n"));
+    }
+
+    private void testSitemap(int index, String expectedContent) throws Exception {
+        MvcResult mvcResult = mockMvc.perform(get("/faidare/germplasms/sitemap-" + index + ".txt")
+                                                  .contextPath("/faidare"))
+                                     .andExpect(request().asyncStarted())
+                                     .andReturn();
+
+        this.mockMvc.perform(asyncDispatch(mvcResult))
+                    .andExpect(status().isOk())
+                    .andExpect(content().contentType(MediaType.TEXT_PLAIN))
+                    .andExpect(content().string(expectedContent));
+    }
+}
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/web/site/SiteControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/web/site/SiteControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..98237eb1ea3d436242e9eb098216a1b3a10de4c8
--- /dev/null
+++ b/backend/src/test/java/fr/inra/urgi/faidare/web/site/SiteControllerTest.java
@@ -0,0 +1,122 @@
+package fr.inra.urgi.faidare.web.site;
+
+import static fr.inra.urgi.faidare.web.Fixtures.htmlContent;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import fr.inra.urgi.faidare.config.FaidareProperties;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.study.StudySitemapVO;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
+import fr.inra.urgi.faidare.domain.response.PaginatedList;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentSearchCriteria;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.repository.es.LocationRepository;
+import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
+import fr.inra.urgi.faidare.utils.Sitemaps;
+import fr.inra.urgi.faidare.web.Fixtures;
+import fr.inra.urgi.faidare.web.thymeleaf.CoordinatesDialect;
+import fr.inra.urgi.faidare.web.thymeleaf.FaidareDialect;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+
+/**
+ * MVC tests for {@link SiteController}
+ * @author JB Nizet
+ */
+@WebMvcTest(SiteController.class)
+public class SiteControllerTest {
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private LocationRepository mockLocationRepository;
+
+    @MockBean
+    private XRefDocumentRepository mockXRefDocumentRepository;
+
+    @MockBean
+    private FaidareProperties mockFaidareProperties;
+
+    private LocationVO site;
+    private List<XRefDocumentVO> crossReferences;
+    private DataSource dataSource;
+
+    @BeforeEach
+    void prepare() {
+        site = Fixtures.createSite();
+        when(mockLocationRepository.getById(site.getLocationDbId())).thenReturn(site);
+
+        crossReferences = Arrays.asList(
+            Fixtures.createXref("foobar"),
+            Fixtures.createXref("bazbing")
+        );
+        when(mockXRefDocumentRepository.find(any()))
+            .thenReturn(new PaginatedList<>(null, crossReferences));
+
+        dataSource = Fixtures.createDataSource();
+        when(mockFaidareProperties.getByUri(site.getSourceUri())).thenReturn(dataSource);
+    }
+
+    @Test
+    void shouldDisplaySite() throws Exception {
+        mockMvc.perform(get("/sites/{id}", site.getLocationDbId()))
+            .andExpect(status().isOk())
+            .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+            .andExpect(htmlContent().hasTitle("Site France"))
+            .andExpect(htmlContent().containsH2s("Details", "Additional info", "Cross references"))
+            .andExpect(htmlContent().endsCorrectly());
+    }
+
+    @Test
+    void shouldGenerateSitemap() throws Exception {
+        List<LocationSitemapVO> sites = Arrays.asList(
+            new LocationSitemapVO("site1"),
+            new LocationSitemapVO("site4"),
+            new LocationSitemapVO("site53"),
+            new LocationSitemapVO("site68")
+        );
+
+        // the hashCode algorithm is specified in the javadoc, so it's guaranteed to be
+        // the same everywhere
+        // uncomment the following line to see which sitemap index each study has
+        // sites.forEach(site -> System.out.println(site.getLocationDbId() + " = " + Math.floorMod(site.getLocationDbId().hashCode(), Sitemaps.BUCKET_COUNT)));
+
+        when(mockLocationRepository.scrollAllForSitemap(anyInt())).thenAnswer(invocation -> sites.iterator());
+        testSitemap(2, "http://localhost/faidare/sites/site1\nhttp://localhost/faidare/sites/site53\n");
+        testSitemap(5, "http://localhost/faidare/sites/site4\nhttp://localhost/faidare/sites/site68\n");
+        testSitemap(7, "");
+
+        mockMvc.perform(get("/faidare/sites/sitemap-17.txt")
+                            .contextPath("/faidare"))
+               .andExpect(status().isNotFound());
+    }
+
+    private void testSitemap(int index, String expectedContent) throws Exception {
+        MvcResult mvcResult = mockMvc.perform(get("/faidare/sites/sitemap-" + index + ".txt")
+                                                  .contextPath("/faidare"))
+                                     .andExpect(request().asyncStarted())
+                                     .andReturn();
+
+        this.mockMvc.perform(asyncDispatch(mvcResult))
+                    .andExpect(status().isOk())
+                    .andExpect(content().contentType(MediaType.TEXT_PLAIN))
+                    .andExpect(content().string(expectedContent));
+
+    }
+}
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/web/sitemap/SitemapIndexControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/web/sitemap/SitemapIndexControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f482c052de0e6e9d832a98adc02978cd1e5cfd80
--- /dev/null
+++ b/backend/src/test/java/fr/inra/urgi/faidare/web/sitemap/SitemapIndexControllerTest.java
@@ -0,0 +1,35 @@
+package fr.inra.urgi.faidare.web.sitemap;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import fr.inra.urgi.faidare.utils.Sitemaps;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+/**
+ * MVC tests for {@link SitemapIndexController}
+ * @author JB Nizet
+ */
+@WebMvcTest(SitemapIndexController.class)
+class SitemapIndexControllerTest {
+    @Autowired
+    private MockMvc mockMvc;
+
+    @Test
+    void shouldGenerateSitemapIndex() throws Exception {
+        mockMvc.perform(get("/faidare/sitemap.xml").contextPath("/faidare"))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.TEXT_XML))
+            .andExpect(xpath("/sitemapindex/sitemap[1]/loc").string("http://localhost/faidare/sites/sitemap-0.txt"))
+            .andExpect(xpath("/sitemapindex/sitemap[2]/loc").string("http://localhost/faidare/sites/sitemap-1.txt"))
+            .andExpect(xpath("/sitemapindex/sitemap[" + (Sitemaps.BUCKET_COUNT + 1) + "]/loc").string("http://localhost/faidare/germplasms/sitemap-0.txt"))
+            .andExpect(xpath("/sitemapindex/sitemap[" + (Sitemaps.BUCKET_COUNT + 2) + "]/loc").string("http://localhost/faidare/germplasms/sitemap-1.txt"))
+            .andExpect(xpath("/sitemapindex/sitemap[" + (Sitemaps.BUCKET_COUNT * 2 + 1) + "]/loc").string("http://localhost/faidare/studies/sitemap-0.txt"))
+            .andExpect(xpath("/sitemapindex/sitemap[" + (Sitemaps.BUCKET_COUNT * 2 + 2) + "]/loc").string("http://localhost/faidare/studies/sitemap-1.txt"));
+    }
+}
diff --git a/backend/src/test/java/fr/inra/urgi/faidare/web/study/StudyControllerTest.java b/backend/src/test/java/fr/inra/urgi/faidare/web/study/StudyControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..784f3cbcd28ac88caaceef3e6ff76b956b68d093
--- /dev/null
+++ b/backend/src/test/java/fr/inra/urgi/faidare/web/study/StudyControllerTest.java
@@ -0,0 +1,243 @@
+package fr.inra.urgi.faidare.web.study;
+
+import static fr.inra.urgi.faidare.web.Fixtures.createSite;
+import static fr.inra.urgi.faidare.web.Fixtures.htmlContent;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import fr.inra.urgi.faidare.config.FaidareProperties;
+import fr.inra.urgi.faidare.domain.data.LocationSitemapVO;
+import fr.inra.urgi.faidare.domain.data.LocationVO;
+import fr.inra.urgi.faidare.domain.data.TrialVO;
+import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
+import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
+import fr.inra.urgi.faidare.domain.data.study.StudySitemapVO;
+import fr.inra.urgi.faidare.domain.data.variable.ObservationVariableVO;
+import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
+import fr.inra.urgi.faidare.domain.response.PaginatedList;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentSearchCriteria;
+import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
+import fr.inra.urgi.faidare.repository.es.GermplasmRepository;
+import fr.inra.urgi.faidare.repository.es.LocationRepository;
+import fr.inra.urgi.faidare.repository.es.StudyRepository;
+import fr.inra.urgi.faidare.repository.es.TrialRepository;
+import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
+import fr.inra.urgi.faidare.repository.file.CropOntologyRepository;
+import fr.inra.urgi.faidare.utils.Sitemaps;
+import fr.inra.urgi.faidare.web.Fixtures;
+import fr.inra.urgi.faidare.web.site.SiteController;
+import fr.inra.urgi.faidare.web.thymeleaf.CoordinatesDialect;
+import fr.inra.urgi.faidare.web.thymeleaf.FaidareDialect;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * MVC tests for {@link StudyController}
+ * @author JB Nizet
+ */
+@WebMvcTest(StudyController.class)
+public class StudyControllerTest {
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private StudyRepository mockStudyRepository;
+
+    @MockBean
+    private FaidareProperties mockFaidareProperties;
+
+    @MockBean
+    private XRefDocumentRepository mockXRefDocumentRepository;
+
+    @MockBean
+    private GermplasmRepository mockGermplasmRepository;
+
+    @MockBean
+    private CropOntologyRepository mockCropOntologyRepository;
+
+    @MockBean
+    private TrialRepository mockTrialRepository;
+
+    @MockBean
+    private LocationRepository mockLocationRepository;
+
+    @Autowired
+    private StudyController studyController;
+
+    private StudyDetailVO study;
+    private GermplasmVO germplasm;
+    private List<XRefDocumentVO> crossReferences;
+    private DataSource dataSource;
+    private LocationVO location;
+    private TrialVO trial;
+
+    @BeforeEach
+    void prepare() {
+        study = Fixtures.createStudy();
+        when(mockStudyRepository.getById(study.getStudyDbId())).thenReturn(study);
+
+        germplasm = Fixtures.createGermplasm();
+        when(mockGermplasmRepository.find(any())).thenReturn(new PaginatedList<>(null, Arrays.asList(germplasm)));
+
+        crossReferences = Arrays.asList(
+            Fixtures.createXref("foobar"),
+            Fixtures.createXref("bazbing")
+        );
+        when(mockXRefDocumentRepository.find(any()))
+            .thenReturn(new PaginatedList<>(null, crossReferences));
+
+        dataSource = Fixtures.createDataSource();
+        when(mockFaidareProperties.getByUri(study.getSourceUri())).thenReturn(dataSource);
+
+        location = Fixtures.createSite();
+        when(mockLocationRepository.getById(study.getLocationDbId())).thenReturn(location);
+
+        trial = Fixtures.createTrial();
+        when(mockTrialRepository.getById(study.getTrialDbIds().iterator().next())).thenReturn(trial);
+
+        Set<String> variableDbIds = Collections.singleton("variable1");
+        when(mockStudyRepository.getVariableIds(study.getStudyDbId())).thenReturn(variableDbIds);
+        when(mockCropOntologyRepository.getVariableByIds(variableDbIds)).thenReturn(
+            Arrays.asList(Fixtures.createVariable())
+        );
+    }
+
+    @Test
+    void shouldDisplayStudy() throws Exception {
+        mockMvc.perform(get("/studies/{id}", study.getStudyDbId()))
+               .andExpect(status().isOk())
+               .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
+               .andExpect(htmlContent().hasTitle("Study Doability: Study 1"))
+               .andExpect(htmlContent().containsH2s("Identification", "Genotype", "Variables", "Data Set", "Contact", "Additional information", "Cross references"))
+               .andExpect(htmlContent().endsCorrectly());
+    }
+
+    @Test
+    void shouldGenerateSitemap() throws Exception {
+        List<StudySitemapVO> studies = Arrays.asList(
+            new StudySitemapVO("study1"),
+            new StudySitemapVO("study4"),
+            new StudySitemapVO("study51"),
+            new StudySitemapVO("study72")
+        );
+
+        // the hashCode algorithm is specified in the javadoc, so it's guaranteed to be
+        // the same everywhere
+        // uncomment the following line to see which sitemap index each study has
+        // studies.forEach(study -> System.out.println(study.getStudyDbId() + " = " + Math.floorMod(study.getStudyDbId().hashCode(), Sitemaps.BUCKET_COUNT)));
+
+        when(mockStudyRepository.scrollAllForSitemap(anyInt())).thenAnswer(invocation -> studies.iterator());
+        testSitemap(6, "http://localhost/faidare/studies/study1\nhttp://localhost/faidare/studies/study72\n");
+        testSitemap(9, "http://localhost/faidare/studies/study4\nhttp://localhost/faidare/studies/study51\n");
+        testSitemap(7, "");
+
+        mockMvc.perform(get("/faidare/studies/sitemap-17.txt")
+                            .contextPath("/faidare"))
+               .andExpect(status().isNotFound());
+    }
+
+    @Nested
+    class Variables {
+        @Test
+        void shouldFilterVariablesByLanguageWhenRequestedLanguageIsFound() throws Exception {
+            ObservationVariableVO variableWithEnglishLanguage = Fixtures.createVariable();
+            variableWithEnglishLanguage.setLanguage("EN");
+
+            ObservationVariableVO variableWithFrenchLanguage = Fixtures.createVariable();
+            variableWithFrenchLanguage.setLanguage("FRA");
+
+            ObservationVariableVO variableWithNoLanguage = Fixtures.createVariable();
+            variableWithNoLanguage.setLanguage(null);
+
+            when(mockCropOntologyRepository.getVariableByIds(any())).thenReturn(
+                Arrays.asList(variableWithEnglishLanguage, variableWithFrenchLanguage, variableWithNoLanguage)
+            );
+
+            ModelAndView modelAndView = mockMvc.perform(get("/studies/{id}", study.getStudyDbId())
+                                                            .locale(Locale.FRENCH))
+                                               .andReturn()
+                                               .getModelAndView();
+            StudyModel model = (StudyModel) modelAndView.getModel().get("model");
+            assertThat(model.getVariables()).containsOnly(variableWithFrenchLanguage, variableWithNoLanguage);
+        }
+
+        @Test
+        void shouldFilterVariablesByLanguageWhenRequestedLanguageIsNotFound() throws Exception {
+            ObservationVariableVO variableWithEnglishLanguage = Fixtures.createVariable();
+            variableWithEnglishLanguage.setLanguage("EN");
+
+            ObservationVariableVO variableWithFrenchLanguage = Fixtures.createVariable();
+            variableWithFrenchLanguage.setLanguage("FRA");
+
+            ObservationVariableVO variableWithNoLanguage = Fixtures.createVariable();
+            variableWithNoLanguage.setLanguage(null);
+
+            when(mockCropOntologyRepository.getVariableByIds(any())).thenReturn(
+                Arrays.asList(variableWithEnglishLanguage, variableWithFrenchLanguage, variableWithNoLanguage)
+            );
+
+            ModelAndView modelAndView = mockMvc.perform(get("/studies/{id}", study.getStudyDbId())
+                                                            .locale(Locale.CHINA))
+                                               .andReturn()
+                                               .getModelAndView();
+            StudyModel model = (StudyModel) modelAndView.getModel().get("model");
+            assertThat(model.getVariables()).containsOnly(variableWithEnglishLanguage, variableWithNoLanguage);
+        }
+
+        @Test
+        void shouldFilterVariablesByLanguageWhenRequestedLanguageIsNotFoundAndEnglishAbsent() throws Exception {
+            ObservationVariableVO variableWithSpanishLanguage = Fixtures.createVariable();
+            variableWithSpanishLanguage.setLanguage("es");
+
+            ObservationVariableVO variableWithFrenchLanguage = Fixtures.createVariable();
+            variableWithFrenchLanguage.setLanguage("FRA");
+
+            ObservationVariableVO variableWithNoLanguage = Fixtures.createVariable();
+            variableWithNoLanguage.setLanguage(null);
+
+            when(mockCropOntologyRepository.getVariableByIds(any())).thenReturn(
+                Arrays.asList(variableWithSpanishLanguage, variableWithFrenchLanguage, variableWithNoLanguage)
+            );
+
+            ModelAndView modelAndView = mockMvc.perform(get("/studies/{id}", study.getStudyDbId())
+                                                            .locale(Locale.CHINA))
+                                               .andReturn()
+                                               .getModelAndView();
+            StudyModel model = (StudyModel) modelAndView.getModel().get("model");
+            assertThat(model.getVariables()).hasSize(2).contains(variableWithNoLanguage);
+        }
+    }
+
+    private void testSitemap(int index, String expectedContent) throws Exception {
+        MvcResult mvcResult = mockMvc.perform(get("/faidare/studies/sitemap-" + index + ".txt")
+                                                  .contextPath("/faidare"))
+                                     .andExpect(request().asyncStarted())
+                                     .andReturn();
+
+        this.mockMvc.perform(asyncDispatch(mvcResult))
+                    .andExpect(status().isOk())
+                    .andExpect(content().contentType(MediaType.TEXT_PLAIN))
+                    .andExpect(content().string(expectedContent));
+
+    }
+}
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/elasticsearch/query/impl/expected/query3.json b/backend/src/test/resources/fr/inra/urgi/faidare/elasticsearch/query/impl/expected/query3.json
index b4977699d6f3ed71f2827c4bc2e44864b7f2818b..2e066801302bf694bcec337405ec4d5f6fbed810 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/elasticsearch/query/impl/expected/query3.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/elasticsearch/query/impl/expected/query3.json
@@ -1,48 +1,49 @@
 {
-  "nested" : {
-    "query" : {
-      "bool" : {
-        "must" : [
+  "nested": {
+    "query": {
+      "bool": {
+        "must": [
           {
-            "term" : {
-              "field2.schema:identifier" : {
-                "value" : "5",
-                "boost" : 1.0
+            "term": {
+              "field2.schema:identifier": {
+                "value": "5",
+                "boost": 1.0
               }
             }
           },
           {
-            "term" : {
-              "field2.field4.subField" : {
-                "value" : "4",
-                "boost" : 1.0
+            "term": {
+              "field2.field4.subField": {
+                "value": "4",
+                "boost": 1.0
               }
             }
           },
           {
-            "term" : {
-              "field2.field3" : {
-                "value" : "3",
-                "boost" : 1.0
+            "term": {
+              "field2.field3": {
+                "value": "3",
+                "boost": 1.0
               }
             }
           }
         ],
-        "adjust_pure_negative" : true,
-        "boost" : 1.0
+        "adjust_pure_negative": true,
+        "boost": 1.0
       }
     },
-    "path" : "field2",
-    "ignore_unmapped" : false,
-    "score_mode" : "none",
-    "boost" : 1.0,
-    "inner_hits" : {
-      "ignore_unmapped" : false,
-      "from" : 0,
-      "size" : 10000,
-      "version" : false,
-      "explain" : false,
-      "track_scores" : false
+    "path": "field2",
+    "ignore_unmapped": false,
+    "score_mode": "none",
+    "boost": 1.0,
+    "inner_hits": {
+      "ignore_unmapped": false,
+      "from": 0,
+      "size": 10000,
+      "version": false,
+      "seq_no_primary_term": false,
+      "explain": false,
+      "track_scores": false
     }
   }
-}
\ No newline at end of file
+}
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/fixture/urgi_xref_test-group0.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/fixture/urgi_xref_test-group0.json
index 05809a8ce030a613e8cb4cc1d2649afe33e08063..a91de2ba3d914716f9b07eec2bef2d7e549b6b36 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/fixture/urgi_xref_test-group0.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/fixture/urgi_xref_test-group0.json
@@ -1,46 +1,28 @@
 [
   {
-    "linkedRessourcesID": [
+    "linkedResourcesID": [
       "ID2"
     ],
-    "group_id": "0",
-    "entry_type": "Accession",
-    "database_name": "GnpIS",
-    "db_id": "ID1",
-    "db_version": "ACCESSION_https://doi.org/10.15454/KFQTFL_1",
+    "groupId": "0",
+    "entryType": "Accession",
+    "databaseName": "GnpIS",
+    "identifier": "ID1",
     "name": "355",
     "description": "Lorem ipsum....",
     "url": "https://urgi.versailles.inra.fr/gnpis-core/#accessionCard/id=aHR0cHM6Ly9kb2kub3JnLzEwLjE1NDU0L0tGUVRGTA==",
-    "species": "Quercus petraea",
-    "xref": "",
-    "feature_type": "",
-    "sequence_id": "",
-    "sequence_version": "",
-    "start_position": "",
-    "end_position": "",
-    "map": "",
-    "map_position": "",
-    "authority": "INRA-UMR1202-BIOGECO (Biodiversité Gènes et Communauté)",
-    "trait": "",
-    "trait_id": "",
-    "environment": "",
-    "environment_id": "",
-    "statistic": "",
-    "unit": "",
-    "genotype": "",
-    "experiment_type": ""
+    "species": "Quercus petraea"
   },
   {
-    "linkedRessourcesID": [
+    "linkedResourcesID": [
       "ID3"
     ],
-    "entry_type": "Site"
+    "entryType": "Site"
   },
   {
-    "linkedRessourcesID": [
+    "linkedResourcesID": [
       "ID2",
       "ID3"
     ],
-    "entry_type": "Site"
+    "entryType": "Site"
   }
 ]
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/datadiscovery_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/datadiscovery_mapping.json
index 076ea76a3a21ac105d82610d6f3205304b9ec993..a6f320ff698518aa6f70a01b94b5c851dde26f49 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/datadiscovery_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/datadiscovery_mapping.json
@@ -1,92 +1,92 @@
 {
-	"datadiscovery": {
-		"dynamic": "false",
-		"_source": {
-			"includes": ["@id", "@type", "schema:*", "groupId"]
-		},
-		"properties": {
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			},
-			"schema:description": {
-				"type": "keyword"
-			},
-
-			"germplasmURI": {
-				"type": "keyword"
-			},
-			"germplasmDbId": {
-				"type": "keyword"
-			},
-			"studyURIs": {
-				"type": "keyword"
-			},
-			"studyDbIds": {
-				"type": "keyword"
-			},
-
-			"germplasm": {
-				"type": "object",
-				"properties": {
-					"cropName": {
-						"type": "keyword",
-						"fields": {
-							"suggest": {
-								"type": "text",
-								"search_analyzer": "search_suggester",
-								"analyzer": "index_suggester"
-							}
-						}
-					},
-					"germplasmList": {
-						"type": "keyword",
-						"fields": {
-							"suggest": {
-								"type": "text",
-								"search_analyzer": "search_suggester",
-								"analyzer": "index_suggester"
-							}
-						}
-					},
-					"accession": {
-						"type": "keyword",
-						"fields": {
-							"suggest": {
-								"type": "text",
-								"search_analyzer": "search_suggester",
-								"analyzer": "index_suggester"
-							}
-						}
-					}
-				}
-			},
-
-			"trait": {
-				"type": "object",
-				"properties": {
-					"observationVariableIds": {
-						"type": "keyword"
-					}
-				}
-			}
-		}
-	}
+  "dynamic": false,
+  "_source": {
+    "includes": [
+      "@id",
+      "@type",
+      "schema:*",
+      "groupId"
+    ]
+  },
+  "properties": {
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    },
+    "schema:description": {
+      "type": "keyword"
+    },
+    "germplasmURI": {
+      "type": "keyword"
+    },
+    "germplasmDbId": {
+      "type": "keyword"
+    },
+    "studyURIs": {
+      "type": "keyword"
+    },
+    "studyDbIds": {
+      "type": "keyword"
+    },
+    "germplasm": {
+      "type": "object",
+      "properties": {
+        "cropName": {
+          "type": "keyword",
+          "fields": {
+            "suggest": {
+              "type": "text",
+              "search_analyzer": "search_suggester",
+              "analyzer": "index_suggester"
+            }
+          }
+        },
+        "germplasmList": {
+          "type": "keyword",
+          "fields": {
+            "suggest": {
+              "type": "text",
+              "search_analyzer": "search_suggester",
+              "analyzer": "index_suggester"
+            }
+          }
+        },
+        "accession": {
+          "type": "keyword",
+          "fields": {
+            "suggest": {
+              "type": "text",
+              "search_analyzer": "search_suggester",
+              "analyzer": "index_suggester"
+            }
+          }
+        }
+      }
+    },
+    "trait": {
+      "type": "object",
+      "properties": {
+        "observationVariableIds": {
+          "type": "keyword"
+        }
+      }
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmAttribute_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmAttribute_mapping.json
index d0133c0bb3e2a0592d960b80e007b1385494494d..9b4883f83f4c94d02b7f06a09f9121731cd665d0 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmAttribute_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmAttribute_mapping.json
@@ -1,68 +1,65 @@
 {
-	"germplasmAttribute": {
-		"dynamic": "strict",
-		"properties": {
-			"germplasmAttributeURI": {
-				"type": "keyword"
-			},
-			"germplasmAttributeDbId": {
-				"type": "keyword"
-			},
-			"germplasmURI": {
-				"type": "keyword"
-			},
-			"germplasmDbId": {
-				"type": "keyword"
-			},
-			"data": {
-				"type": "nested",
-				"properties": {
-					"attributeURI": {
-						"type": "keyword"
-					},
-					"attributeDbId": {
-						"type": "keyword"
-					},
-					"attributeCode": {
-						"type": "keyword"
-					},
-					"attributeName": {
-						"type": "keyword"
-					},
-					"determinedDate": {
-						"type": "date",
-						"format": "YYYY-MM-dd"
-					},
-					"value": {
-						"type": "keyword"
-					}
-				}
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "germplasmAttributeURI": {
+      "type": "keyword"
+    },
+    "germplasmAttributeDbId": {
+      "type": "keyword"
+    },
+    "germplasmURI": {
+      "type": "keyword"
+    },
+    "germplasmDbId": {
+      "type": "keyword"
+    },
+    "data": {
+      "type": "nested",
+      "properties": {
+        "attributeURI": {
+          "type": "keyword"
+        },
+        "attributeDbId": {
+          "type": "keyword"
+        },
+        "attributeCode": {
+          "type": "keyword"
+        },
+        "attributeName": {
+          "type": "keyword"
+        },
+        "determinedDate": {
+          "type": "date",
+          "format": "YYYY-MM-dd"
+        },
+        "value": {
+          "type": "keyword"
+        }
+      }
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmMcpd_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmMcpd_mapping.json
index e26ea0b6ab897bd65e7bfd81a90b4c2575eeb0c1..acface400a728cde1de8daf376b67e66ff4c1f31 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmMcpd_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmMcpd_mapping.json
@@ -1,455 +1,450 @@
 {
-  "germplasmMcpd": {
-    "dynamic": "false",
-    "properties": {
-      "germplasmURI": {
-        "type": "keyword"
-      },
-      "germplasmName": {
-        "type": "keyword",
-        "doc_values": true
-      },
-      "accessionNames": {
-        "type": "keyword",
-        "doc_values": true
-      },
-      "accessionNumber": {
-        "type": "keyword",
-        "doc_values": true
-      },
-      "acquisitionDate": {
-        "type": "integer"
-      },
-      "acquisitionSourceCode": {
-        "type": "keyword"
-      },
-      "alternateIDs": {
-        "type": "keyword"
-      },
-      "ancestralData": {
-        "type": "keyword"
-      },
-      "biologicalStatusOfAccessionCode": {
-        "type": "keyword"
-      },
-      "breedingInstitutes": {
-        "properties": {
-          "instituteCode": {
-            "type": "keyword"
-          },
-          "instituteName": {
-            "type": "keyword"
-          },
-          "acronym": {
-            "type": "keyword"
-          },
-          "organisation": {
-            "type": "keyword"
-          },
-          "instituteType": {
-            "type": "keyword"
-          },
-          "webSite": {
-            "type": "keyword"
-          },
-          "instituteAddress": {
-            "type": "keyword"
-          },
-          "logo": {
-            "type": "keyword"
-          }
+  "dynamic": false,
+  "properties": {
+    "germplasmURI": {
+      "type": "keyword"
+    },
+    "germplasmName": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "accessionNames": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "accessionNumber": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "acquisitionDate": {
+      "type": "integer"
+    },
+    "acquisitionSourceCode": {
+      "type": "keyword"
+    },
+    "alternateIDs": {
+      "type": "keyword"
+    },
+    "ancestralData": {
+      "type": "keyword"
+    },
+    "biologicalStatusOfAccessionCode": {
+      "type": "keyword"
+    },
+    "breedingInstitutes": {
+      "properties": {
+        "instituteCode": {
+          "type": "keyword"
+        },
+        "instituteName": {
+          "type": "keyword"
+        },
+        "acronym": {
+          "type": "keyword"
+        },
+        "organisation": {
+          "type": "keyword"
+        },
+        "instituteType": {
+          "type": "keyword"
+        },
+        "webSite": {
+          "type": "keyword"
+        },
+        "instituteAddress": {
+          "type": "keyword"
+        },
+        "logo": {
+          "type": "keyword"
         }
-      },
-      "breedingMethodDbId": {
-        "type": "keyword"
-      },
-      "breederAccessionNumber": {
-        "type": "keyword"
-      },
-      "breedingCreationYear": {
-        "type": "keyword"
-      },
-      "catalogRegistrationYear": {
-        "type": "keyword"
-      },
-      "catalogDeregistrationYear": {
-        "type": "keyword"
-      },
-      "collectingInfo": {
-        "properties": {
-          "collectingDate": {
-            "type": "integer"
-          },
-          "collectingInstitutes": {
-            "properties": {
-              "instituteCode": {
-                "type": "keyword"
-              },
-              "instituteName": {
-                "type": "keyword"
-              },
-              "acronym": {
-                "type": "keyword"
-              },
-              "organisation": {
-                "type": "keyword"
-              },
-              "instituteType": {
-                "type": "keyword"
-              },
-              "webSite": {
-                "type": "keyword"
-              },
-              "instituteAddress": {
-                "type": "keyword"
-              },
-              "logo": {
-                "type": "keyword"
-              }
+      }
+    },
+    "breedingMethodDbId": {
+      "type": "keyword"
+    },
+    "breederAccessionNumber": {
+      "type": "keyword"
+    },
+    "breedingCreationYear": {
+      "type": "keyword"
+    },
+    "catalogRegistrationYear": {
+      "type": "keyword"
+    },
+    "catalogDeregistrationYear": {
+      "type": "keyword"
+    },
+    "collectingInfo": {
+      "properties": {
+        "collectingDate": {
+          "type": "integer"
+        },
+        "collectingInstitutes": {
+          "properties": {
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "instituteName": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "instituteAddress": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
             }
-          },
-          "collectingMissionIdentifier": {
-            "type": "keyword"
-          },
-          "collectingNumber": {
-            "type": "keyword"
-          },
-          "collectors": {
-            "type": "keyword"
-          },
-          "materialType": {
-            "type": "keyword"
-          },
-          "collectingSite": {
-            "properties": {
-              "locationDbId": {
-                "type": "keyword"
-              },
-              "locationName": {
-                "type": "keyword"
-              },
-              "coordinateUncertainty": {
-                "type": "keyword"
-              },
-              "elevation": {
-                "type": "keyword"
-              },
-              "georeferencingMethod":{
-                "type": "keyword"
-              },
-              "latitudeDecimal": {
-                "type": "keyword"
-              },
-              "latitudeDegrees": {
-                "type": "keyword"
-              },
-              "locationDescription": {
-                "type": "keyword"
-              },
-              "longitudeDecimal":  {
-                "type": "keyword"
-              },
-              "longitudeDegrees":  {
-                "type": "keyword"
-              },
-              "spatialReferenceSystem": {
-                "type": "keyword"
-              },
-              "locationURI": {
-                "type": "keyword"
-              }
-
+          }
+        },
+        "collectingMissionIdentifier": {
+          "type": "keyword"
+        },
+        "collectingNumber": {
+          "type": "keyword"
+        },
+        "collectors": {
+          "type": "keyword"
+        },
+        "materialType": {
+          "type": "keyword"
+        },
+        "collectingSite": {
+          "properties": {
+            "locationDbId": {
+              "type": "keyword"
+            },
+            "locationName": {
+              "type": "keyword"
+            },
+            "coordinateUncertainty": {
+              "type": "keyword"
+            },
+            "elevation": {
+              "type": "keyword"
+            },
+            "georeferencingMethod": {
+              "type": "keyword"
+            },
+            "latitudeDecimal": {
+              "type": "keyword"
+            },
+            "latitudeDegrees": {
+              "type": "keyword"
+            },
+            "locationDescription": {
+              "type": "keyword"
+            },
+            "longitudeDecimal": {
+              "type": "keyword"
+            },
+            "longitudeDegrees": {
+              "type": "keyword"
+            },
+            "spatialReferenceSystem": {
+              "type": "keyword"
+            },
+            "locationURI": {
+              "type": "keyword"
             }
-
           }
-
         }
-      },
-      "commonCropName": {
-        "type": "keyword",
-        "doc_values": true
-      },
-      "countryOfOrigin": {
-        "type": "keyword"
-      },
-      "countryOfOriginCode": {
-        "type": "keyword"
-      },
-      "originLocationDbId": {
-        "type": "keyword"
-      },
-      "originLocationName": {
-        "type": "keyword"
-      },
-      "documentationURL": {
-        "type": "keyword"
-      },
-      "donors": {
-        "properties": {
-          "donorInstituteCode": {
-            "type": "keyword"
-          },
-          "donorGermplasmPUI": {
-            "type": "keyword"
-          },
-          "germplasmPUI": {
-            "type": "keyword"
-          },
-          "donorAccessionNumber": {
-            "type": "keyword"
-          },
-          "donorInstitute": {
-            "properties": {
-              "instituteName": {
-                "type": "keyword"
-              },
-              "instituteCode": {
-                "type": "keyword"
-              },
-              "acronym": {
-                "type": "keyword"
-              },
-              "organisation": {
-                "type": "keyword"
-              },
-              "instituteType": {
-                "type": "keyword"
-              },
-              "webSite": {
-                "type": "keyword"
-              },
-              "address": {
-                "type": "keyword"
-              },
-              "logo": {
-                "type": "keyword"
-              }
+      }
+    },
+    "commonCropName": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "countryOfOrigin": {
+      "type": "keyword"
+    },
+    "countryOfOriginCode": {
+      "type": "keyword"
+    },
+    "originLocationDbId": {
+      "type": "keyword"
+    },
+    "originLocationName": {
+      "type": "keyword"
+    },
+    "documentationURL": {
+      "type": "keyword"
+    },
+    "donors": {
+      "properties": {
+        "donorInstituteCode": {
+          "type": "keyword"
+        },
+        "donorGermplasmPUI": {
+          "type": "keyword"
+        },
+        "germplasmPUI": {
+          "type": "keyword"
+        },
+        "donorAccessionNumber": {
+          "type": "keyword"
+        },
+        "donorInstitute": {
+          "properties": {
+            "instituteName": {
+              "type": "keyword"
+            },
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "address": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
             }
-          },
-          "donationDate": {
-            "type": "integer"
           }
+        },
+        "donationDate": {
+          "type": "integer"
         }
-      },
-      "donorInfo": {
-        "properties":{
-          "donorAccessionNumber": {
-            "type": "keyword"
-          },
-          "donorAccessionPui": {
-            "type": "keyword"
-          },
-          "donationDate": {
-            "type": "keyword"
-          },
-          "donorInstitute": {
-            "properties":{
-              "instituteCode": {
-                "type": "keyword"
-              },
-              "instituteName": {
-                "type": "keyword"
-              },
-              "acronym": {
-                "type": "keyword"
-              },
-              "organisation": {
-                "type": "keyword"
-              },
-              "instituteType": {
-                "type": "keyword"
-              },
-              "webSite": {
-                "type": "keyword"
-              },
-              "instituteAddress": {
-                "type": "keyword"
-              },
-              "logo": {
-                "type": "keyword"
-              }
+      }
+    },
+    "donorInfo": {
+      "properties": {
+        "donorAccessionNumber": {
+          "type": "keyword"
+        },
+        "donorAccessionPui": {
+          "type": "keyword"
+        },
+        "donationDate": {
+          "type": "keyword"
+        },
+        "donorInstitute": {
+          "properties": {
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "instituteName": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "instituteAddress": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
             }
           }
         }
-      },
-      "genus":{
-        "type": "keyword",
-        "doc_values": true
-      },
-      "genusSpecies": {
-        "type": "keyword",
-        "doc_values": true
-      },
-      "germplasmDbId": {
-        "type": "keyword"
-      },
-      "germplasmMcpdDbId": {
-        "type": "keyword"
-      },
-      "germplasmMcpdURI": {
-        "type": "keyword"
-      },
-      "germplasmGenus": {
-        "type": "keyword",
-        "doc_values": true
-      },
-      "germplasmPUI": {
-        "type": "keyword"
-      },
-      "germplasmSpecies": {
-        "type": "keyword",
-        "doc_values": true
-      },
-      "holdingInstitute": {
-        "properties": {
-          "instituteName": {
-            "type": "keyword"
-          },
-          "instituteCode": {
-            "type": "keyword"
-          },
-          "acronym": {
-            "type": "keyword"
-          },
-          "organisation": {
-            "type": "keyword"
-          },
-          "instituteType": {
-            "type": "keyword"
-          },
-          "webSite": {
-            "type": "keyword"
-          },
-          "instituteAddress": {
-            "type": "keyword"
-          },
-          "logo": {
-            "type": "keyword"
-          }
+      }
+    },
+    "genus": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "genusSpecies": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "germplasmDbId": {
+      "type": "keyword"
+    },
+    "germplasmMcpdDbId": {
+      "type": "keyword"
+    },
+    "germplasmMcpdURI": {
+      "type": "keyword"
+    },
+    "germplasmGenus": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "germplasmPUI": {
+      "type": "keyword"
+    },
+    "germplasmSpecies": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "holdingInstitute": {
+      "properties": {
+        "instituteName": {
+          "type": "keyword"
+        },
+        "instituteCode": {
+          "type": "keyword"
+        },
+        "acronym": {
+          "type": "keyword"
+        },
+        "organisation": {
+          "type": "keyword"
+        },
+        "instituteType": {
+          "type": "keyword"
+        },
+        "webSite": {
+          "type": "keyword"
+        },
+        "instituteAddress": {
+          "type": "keyword"
+        },
+        "logo": {
+          "type": "keyword"
         }
-      },
-      "holdingGenbank": {
-        "properties": {
-          "instituteName": {
-            "type": "keyword",
-            "doc_values": true
-          },
-          "instituteCode": {
-            "type": "keyword"
-          },
-          "webSite": {
-            "type": "keyword"
-          },
-          "logo": {
-            "type": "keyword"
-          }
+      }
+    },
+    "holdingGenbank": {
+      "properties": {
+        "instituteName": {
+          "type": "keyword",
+          "doc_values": true
+        },
+        "instituteCode": {
+          "type": "keyword"
+        },
+        "webSite": {
+          "type": "keyword"
+        },
+        "logo": {
+          "type": "keyword"
         }
-      },
-      "distributorInfos": {
-        "properties": {
-          "institute": {
-            "properties": {
-              "instituteName": {
-                "type": "keyword"
-              },
-              "instituteCode": {
-                "type": "keyword"
-              },
-              "acronym": {
-                "type": "keyword"
-              },
-              "organisation": {
-                "type": "keyword"
-              },
-              "instituteType": {
-                "type": "keyword"
-              },
-              "webSite": {
-                "type": "keyword"
-              },
-              "instituteAddress": {
-                "type": "keyword"
-              },
-              "logo": {
-                "type": "keyword"
-              }
+      }
+    },
+    "distributorInfos": {
+      "properties": {
+        "institute": {
+          "properties": {
+            "instituteName": {
+              "type": "keyword"
+            },
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "instituteAddress": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
             }
-          },
-          "accessionNumber": {
-            "type": "keyword"
-          },
-          "distributionStatus": {
-            "type": "keyword"
           }
+        },
+        "accessionNumber": {
+          "type": "keyword"
+        },
+        "distributionStatus": {
+          "type": "keyword"
         }
-      },
-      "instituteCode": {
-        "type": "keyword"
-      },
-      "mlsStatus": {
-        "type": "keyword"
-      },
-      "remarks": {
-        "type": "keyword"
-      },
-      "safetyDuplicateInstitutes": {
-        "properties":{
-          "instituteCode": {
-            "type": "keyword"
-          },
-          "instituteName": {
-            "type": "keyword"
-          }
+      }
+    },
+    "instituteCode": {
+      "type": "keyword"
+    },
+    "mlsStatus": {
+      "type": "keyword"
+    },
+    "remarks": {
+      "type": "keyword"
+    },
+    "safetyDuplicateInstitutes": {
+      "properties": {
+        "instituteCode": {
+          "type": "keyword"
+        },
+        "instituteName": {
+          "type": "keyword"
         }
-      },
-      "geneticNature": {
-        "type": "keyword"
-      },
-      "species": {
-        "type": "keyword"
-      },
-      "speciesAuthority": {
-        "type": "keyword"
-      },
-      "storageTypeCodes": {
-        "type": "keyword"
-      },
-      "subtaxon": {
-        "type": "keyword"
-      },
-      "subtaxonAuthority": {
-        "type": "keyword"
-      },
-      "subtaxaAuthority": {
-        "type": "keyword"
-      },
-      "groupId": {
-        "type": "long"
-      },
-      "presenceStatus": {
-        "type": "keyword"
-      },
-      "@type": {
-        "type": "keyword"
-      },
-      "@id": {
-        "type": "keyword"
-      },
-      "schema:includedInDataCatalog": {
-        "type": "keyword"
-      },
-      "schema:identifier": {
-        "type": "keyword"
-      },
-      "schema:name": {
-        "type": "keyword"
-      },
-      "schema:url": {
-        "type": "keyword"
-      },
-      "defaultDisplayName": {
-        "type": "keyword"
       }
+    },
+    "geneticNature": {
+      "type": "keyword"
+    },
+    "species": {
+      "type": "keyword"
+    },
+    "speciesAuthority": {
+      "type": "keyword"
+    },
+    "storageTypeCodes": {
+      "type": "keyword"
+    },
+    "subtaxon": {
+      "type": "keyword"
+    },
+    "subtaxonAuthority": {
+      "type": "keyword"
+    },
+    "subtaxaAuthority": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "presenceStatus": {
+      "type": "keyword"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    },
+    "defaultDisplayName": {
+      "type": "keyword"
     }
   }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmPedigree_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmPedigree_mapping.json
index 79986a17f373b0614bd6d2385c39b1a41b56bb83..7e078c2d4e0e526881f682a03975d304a996dfe8 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmPedigree_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmPedigree_mapping.json
@@ -1,96 +1,93 @@
 {
-	"germplasmPedigree": {
-		"dynamic": "strict",
-		"properties": {
-			"germplasmPedigreeURI": {
-				"type": "keyword"
-			},
-			"germplasmPedigreeDbId": {
-				"type": "keyword"
-			},
-			"germplasmURI": {
-				"type": "keyword"
-			},
-			"germplasmDbId": {
-				"type": "keyword"
-			},
-			"defaultDisplayName": {
-				"type": "keyword"
-			},
-			"crossingPlan": {
-				"type": "keyword"
-			},
-			"crossingYear": {
-				"type": "keyword"
-			},
-			"familyCode": {
-				"type": "keyword"
-			},
-			"parent1URI": {
-				"type": "keyword"
-			},
-			"parent1DbId": {
-				"type": "keyword"
-			},
-			"parent1Name": {
-				"type": "keyword"
-			},
-			"parent1Type": {
-				"type": "keyword"
-			},
-			"parent2URI": {
-				"type": "keyword"
-			},
-			"parent2DbId": {
-				"type": "keyword"
-			},
-			"parent2Name": {
-				"type": "keyword"
-			},
-			"parent2Type": {
-				"type": "keyword"
-			},
-			"pedigree": {
-				"type": "keyword"
-			},
-			"siblings": {
-				"properties": {
-					"germplasmURI": {
-						"type": "keyword"
-					},
-					"germplasmDbId": {
-						"type": "keyword"
-					},
-					"defaultDisplayName": {
-						"type": "keyword"
-					}
-				}
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "germplasmPedigreeURI": {
+      "type": "keyword"
+    },
+    "germplasmPedigreeDbId": {
+      "type": "keyword"
+    },
+    "germplasmURI": {
+      "type": "keyword"
+    },
+    "germplasmDbId": {
+      "type": "keyword"
+    },
+    "defaultDisplayName": {
+      "type": "keyword"
+    },
+    "crossingPlan": {
+      "type": "keyword"
+    },
+    "crossingYear": {
+      "type": "keyword"
+    },
+    "familyCode": {
+      "type": "keyword"
+    },
+    "parent1URI": {
+      "type": "keyword"
+    },
+    "parent1DbId": {
+      "type": "keyword"
+    },
+    "parent1Name": {
+      "type": "keyword"
+    },
+    "parent1Type": {
+      "type": "keyword"
+    },
+    "parent2URI": {
+      "type": "keyword"
+    },
+    "parent2DbId": {
+      "type": "keyword"
+    },
+    "parent2Name": {
+      "type": "keyword"
+    },
+    "parent2Type": {
+      "type": "keyword"
+    },
+    "pedigree": {
+      "type": "keyword"
+    },
+    "siblings": {
+      "properties": {
+        "germplasmURI": {
+          "type": "keyword"
+        },
+        "germplasmDbId": {
+          "type": "keyword"
+        },
+        "defaultDisplayName": {
+          "type": "keyword"
+        }
+      }
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmProgeny_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmProgeny_mapping.json
index 58eb7a9b73713a0c9cf9220f9813c38349ca0c55..cdc87f416d0d1bd204b311cca3327e01bb95aba6 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmProgeny_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasmProgeny_mapping.json
@@ -1,63 +1,60 @@
 {
-	"germplasmProgeny": {
-		"dynamic": "strict",
-		"properties": {
-			"germplasmProgenyURI": {
-				"type": "keyword"
-			},
-			"germplasmProgenyDbId": {
-				"type": "keyword"
-			},
-			"germplasmURI": {
-				"type": "keyword"
-			},
-			"germplasmDbId": {
-				"type": "keyword"
-			},
-			"defaultDisplayName": {
-				"type": "keyword"
-			},
-			"progeny": {
-				"properties": {
-					"germplasmURI": {
-						"type": "keyword"
-					},
-					"germplasmDbId": {
-						"type": "keyword"
-					},
-					"defaultDisplayName": {
-						"type": "keyword"
-					},
-					"parentType": {
-						"type": "keyword"
-					}
-				}
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "germplasmProgenyURI": {
+      "type": "keyword"
+    },
+    "germplasmProgenyDbId": {
+      "type": "keyword"
+    },
+    "germplasmURI": {
+      "type": "keyword"
+    },
+    "germplasmDbId": {
+      "type": "keyword"
+    },
+    "defaultDisplayName": {
+      "type": "keyword"
+    },
+    "progeny": {
+      "properties": {
+        "germplasmURI": {
+          "type": "keyword"
+        },
+        "germplasmDbId": {
+          "type": "keyword"
+        },
+        "defaultDisplayName": {
+          "type": "keyword"
+        },
+        "parentType": {
+          "type": "keyword"
+        }
+      }
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasm_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasm_mapping.json
index ab6abaf77b9fd90ccefa0eb08793644490fdb39c..d902ed3d49bdaec9b0b253edb4ff6e8596a742e7 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasm_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/germplasm_mapping.json
@@ -1,617 +1,613 @@
 {
-	"germplasm": {
-		"dynamic": "strict",
-		"properties": {
-			"germplasmURI": {
-				"type": "keyword"
-			},
-			"germplasmDbId": {
-				"type": "keyword"
-			},
-			"germplasmPUI": {
-				"type": "keyword"
-			},
-			"germplasmName": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"accessionNumber": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"acquisitionDate": {
-				"type": "keyword"
-			},
-			"biologicalStatusOfAccessionCode": {
-				"type": "keyword"
-			},
-			"breedingMethodDbId": {
-				"type": "keyword"
-			},
-			"commonCropName": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"countryOfOriginCode": {
-				"type": "keyword"
-			},
-			"countryOfOrigin": {
-				"type": "keyword"
-			},
-			"defaultDisplayName": {
-				"type": "keyword"
-			},
-			"documentationURL": {
-				"type": "keyword"
-			},
-			"donors": {
-				"properties": {
-					"donorInstituteCode": {
-						"type": "keyword"
-					},
-					"donorGermplasmPUI": {
-						"type": "keyword"
-					},
-					"germplasmPUI": {
-						"type": "keyword"
-					},
-					"donorAccessionNumber": {
-						"type": "keyword"
-					},
-					"donorInstitute": {
-						"properties": {
-							"instituteName": {
-								"type": "keyword"
-							},
-							"instituteCode": {
-								"type": "keyword"
-							},
-							"acronym": {
-								"type": "keyword"
-							},
-							"organisation": {
-								"type": "keyword"
-							},
-							"instituteType": {
-								"type": "keyword"
-							},
-							"webSite": {
-								"type": "keyword"
-							},
-							"address": {
-								"type": "keyword"
-							},
-							"logo": {
-								"type": "keyword"
-							}
-						}
-					},
-					"donationDate": {
-						"type": "integer"
-					}
-				}
-			},
-			"genus": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"germplasmGenus": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"species": {
-				"type": "keyword"
-			},
-			"germplasmSpecies": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"genusSpecies": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"speciesAuthority": {
-				"type": "keyword"
-			},
-			"subtaxa": {
-				"type": "keyword"
-			},
-			"subTaxa": {
-				"type": "keyword"
-			},
-			"genusSpeciesSubtaxa": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"subtaxaAuthority": {
-				"type": "keyword"
-			},
-			"instituteCode": {
-				"type": "keyword"
-			},
-			"instituteName": {
-				"type": "keyword"
-			},
-			"pedigree": {
-				"type": "keyword"
-			},
-			"seedSource": {
-				"type": "keyword"
-			},
-			"SeedSource": {
-				"type": "keyword"
-			},
-			"synonyms": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"taxonIds": {
-				"properties": {
-					"sourceName": {
-						"type": "keyword"
-					},
-					"taxonId": {
-						"type": "keyword"
-					}
-				}
-			},
-			"taxonSynonyms": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"taxonCommonNames": {
-				"type": "keyword",
-				"doc_values": true
-			},
-			"taxonComment": {
-				"type": "keyword"
-			},
-			"typeOfGermplasmStorageCode": {
-				"type": "keyword"
-			},
-			"geneticNature": {
-				"type": "keyword"
-			},
-			"comment": {
-				"type": "keyword"
-			},
-			"photo": {
-				"properties": {
-					"file": {
-						"type": "keyword"
-					},
-					"thumbnailFile": {
-						"type": "keyword"
-					},
-					"photoName": {
-						"type": "keyword"
-					},
-					"description": {
-						"type": "keyword"
-					},
-					"copyright": {
-						"type": "keyword"
-					}
-				}
-			},
-			"holdingInstitute": {
-				"properties": {
-					"instituteName": {
-						"type": "keyword"
-					},
-					"instituteCode": {
-						"type": "keyword"
-					},
-					"acronym": {
-						"type": "keyword"
-					},
-					"organisation": {
-						"type": "keyword"
-					},
-					"instituteType": {
-						"type": "keyword"
-					},
-					"webSite": {
-						"type": "keyword"
-					},
-					"address": {
-						"type": "keyword"
-					},
-					"logo": {
-						"type": "keyword"
-					}
-				}
-			},
-			"holdingGenbank": {
-				"properties": {
-					"instituteName": {
-						"type": "keyword",
-						"doc_values": true
-					},
-					"instituteCode": {
-						"type": "keyword"
-					},
-					"webSite": {
-						"type": "keyword"
-					},
-					"logo": {
-						"type": "keyword"
-					}
-				}
-			},
-			"presenceStatus": {
-				"type": "keyword"
-			},
-			"genealogy": {
-				"properties": {
-					"crossingPlan": {
-						"type": "keyword"
-					},
-					"crossingYear": {
-						"type": "keyword"
-					},
-					"familyCode": {
-						"type": "keyword"
-					},
-					"firstParentName": {
-						"type": "keyword"
-					},
-					"firstParentPUI": {
-						"type": "keyword"
-					},
-					"firstParentType": {
-						"type": "keyword"
-					},
-					"secondParentName": {
-						"type": "keyword"
-					},
-					"secondParentPUI": {
-						"type": "keyword"
-					},
-					"secondParentType": {
-						"type": "keyword"
-					},
-					"sibblings": {
-						"properties": {
-							"pui": {
-								"type": "keyword"
-							},
-							"name": {
-								"type": "keyword"
-							}
-						}
-					}
-				}
-			},
-			"children": {
-				"properties": {
-					"firstParentName": {
-						"type": "keyword"
-					},
-					"firstParentPUI": {
-						"type": "keyword"
-					},
-					"secondParentName": {
-						"type": "keyword"
-					},
-					"secondParentPUI": {
-						"type": "keyword"
-					},
-					"sibblings": {
-						"properties": {
-							"pui": {
-								"type": "keyword"
-							},
-							"name": {
-								"type": "keyword"
-							}
-						}
-					}
-				}
-			},
-			"descriptors": {
-				"properties": {
-					"name": {
-						"type": "keyword"
-					},
-					"value": {
-						"type": "keyword"
-					}
-				}
-			},
-			"originSite": {
-				"properties": {
-					"siteId": {
-						"type": "long"
-					},
-					"siteName": {
-						"type": "keyword"
-					},
-					"latitude": {
-						"type": "float"
-					},
-					"longitude": {
-						"type": "float"
-					},
-					"siteType": {
-						"type": "keyword"
-					}
-				}
-			},
-			"collectingSite": {
-				"properties": {
-					"siteId": {
-						"type": "long"
-					},
-					"siteName": {
-						"type": "keyword"
-					},
-					"latitude": {
-						"type": "float"
-					},
-					"longitude": {
-						"type": "float"
-					},
-					"siteType": {
-						"type": "keyword"
-					}
-				}
-			},
-			"evaluationSites": {
-				"properties": {
-					"siteId": {
-						"type": "long"
-					},
-					"siteName": {
-						"type": "keyword"
-					},
-					"latitude": {
-						"type": "float"
-					},
-					"longitude": {
-						"type": "float"
-					},
-					"siteType": {
-						"type": "keyword"
-					}
-				}
-			},
-			"collector": {
-				"properties": {
-					"institute": {
-						"properties": {
-							"instituteName": {
-								"type": "keyword"
-							},
-							"instituteCode": {
-								"type": "keyword"
-							},
-							"acronym": {
-								"type": "keyword"
-							},
-							"organisation": {
-								"type": "keyword"
-							},
-							"instituteType": {
-								"type": "keyword"
-							},
-							"webSite": {
-								"type": "keyword"
-							},
-							"address": {
-								"type": "keyword"
-							},
-							"logo": {
-								"type": "keyword"
-							}
-						}
-					},
-					"accessionNumber": {
-						"type": "keyword"
-					},
-					"accessionCreationDate": {
-						"type": "integer"
-					},
-					"materialType": {
-						"type": "keyword"
-					},
-					"collectors": {
-						"type": "keyword"
-					}
-				}
-			},
-			"breeder": {
-				"properties": {
-					"institute": {
-						"properties": {
-							"instituteName": {
-								"type": "keyword"
-							},
-							"instituteCode": {
-								"type": "keyword"
-							},
-							"acronym": {
-								"type": "keyword"
-							},
-							"organisation": {
-								"type": "keyword"
-							},
-							"instituteType": {
-								"type": "keyword"
-							},
-							"webSite": {
-								"type": "keyword"
-							},
-							"address": {
-								"type": "keyword"
-							},
-							"logo": {
-								"type": "keyword"
-							}
-						}
-					},
-					"accessionNumber": {
-						"type": "keyword"
-					},
-					"accessionCreationDate": {
-						"type": "integer"
-					},
-					"registrationYear": {
-						"type": "integer"
-					},
-					"deregistrationYear": {
-						"type": "integer"
-					}
-				}
-			},
-			"distributors": {
-				"properties": {
-					"institute": {
-						"properties": {
-							"instituteName": {
-								"type": "keyword"
-							},
-							"instituteCode": {
-								"type": "keyword"
-							},
-							"acronym": {
-								"type": "keyword"
-							},
-							"organisation": {
-								"type": "keyword"
-							},
-							"instituteType": {
-								"type": "keyword"
-							},
-							"webSite": {
-								"type": "keyword"
-							},
-							"address": {
-								"type": "keyword"
-							},
-							"logo": {
-								"type": "keyword"
-							}
-						}
-					},
-					"accessionNumber": {
-						"type": "keyword"
-					},
-					"distributionStatus": {
-						"type": "keyword"
-					}
-				}
-			},
-			"panel": {
-				"properties": {
-					"id": {
-						"type": "long"
-					},
-					"name": {
-						"type": "keyword",
-						"doc_values": true
-					},
-					"germplasmCount": {
-						"type": "integer"
-					}
-				}
-			},
-			"collection": {
-				"properties": {
-					"id": {
-						"type": "long"
-					},
-					"name": {
-						"type": "keyword",
-						"doc_values": true
-					},
-					"type": {
-						"type": "keyword"
-					},
-					"germplasmCount": {
-						"type": "integer"
-					}
-				}
-			},
-			"population": {
-				"properties": {
-					"id": {
-						"type": "long"
-					},
-					"name": {
-						"type": "keyword",
-						"doc_values": true
-					},
-					"type": {
-						"type": "keyword"
-					},
-					"germplasmRef": {
-						"properties": {
-							"pui": {
-								"type": "keyword"
-							},
-							"name": {
-								"type": "keyword"
-							}
-						}
-					},
-					"germplasmCount": {
-						"type": "integer"
-					}
-				}
-			},
-			"xref": {
-				"properties": {
-                                        "id": {
-						"type": "keyword"
-					},
-					"source": {
-						"type": "keyword"
-					}
-				}
-                        },
-			"additionalInfo": {
-                                "dynamic": "true",
-                                "properties": {}
-                        },
-
-			"studyURIs": {
-				"type": "keyword"
-			},
-			"studyDbIds": {
-				"type": "keyword"
-			},
-			"studyURI": {
-				"type": "keyword"
-			},
-			"studyDbId": {
-				"type": "keyword"
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "germplasmURI": {
+      "type": "keyword"
+    },
+    "germplasmDbId": {
+      "type": "keyword"
+    },
+    "germplasmPUI": {
+      "type": "keyword"
+    },
+    "germplasmName": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "accessionNumber": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "acquisitionDate": {
+      "type": "keyword"
+    },
+    "biologicalStatusOfAccessionCode": {
+      "type": "keyword"
+    },
+    "breedingMethodDbId": {
+      "type": "keyword"
+    },
+    "commonCropName": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "countryOfOriginCode": {
+      "type": "keyword"
+    },
+    "countryOfOrigin": {
+      "type": "keyword"
+    },
+    "defaultDisplayName": {
+      "type": "keyword"
+    },
+    "documentationURL": {
+      "type": "keyword"
+    },
+    "donors": {
+      "properties": {
+        "donorInstituteCode": {
+          "type": "keyword"
+        },
+        "donorGermplasmPUI": {
+          "type": "keyword"
+        },
+        "germplasmPUI": {
+          "type": "keyword"
+        },
+        "donorAccessionNumber": {
+          "type": "keyword"
+        },
+        "donorInstitute": {
+          "properties": {
+            "instituteName": {
+              "type": "keyword"
+            },
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "address": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
+            }
+          }
+        },
+        "donationDate": {
+          "type": "integer"
+        }
+      }
+    },
+    "genus": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "germplasmGenus": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "species": {
+      "type": "keyword"
+    },
+    "germplasmSpecies": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "genusSpecies": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "speciesAuthority": {
+      "type": "keyword"
+    },
+    "subtaxa": {
+      "type": "keyword"
+    },
+    "subTaxa": {
+      "type": "keyword"
+    },
+    "genusSpeciesSubtaxa": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "subtaxaAuthority": {
+      "type": "keyword"
+    },
+    "instituteCode": {
+      "type": "keyword"
+    },
+    "instituteName": {
+      "type": "keyword"
+    },
+    "pedigree": {
+      "type": "keyword"
+    },
+    "seedSource": {
+      "type": "keyword"
+    },
+    "SeedSource": {
+      "type": "keyword"
+    },
+    "synonyms": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "taxonIds": {
+      "properties": {
+        "sourceName": {
+          "type": "keyword"
+        },
+        "taxonId": {
+          "type": "keyword"
+        }
+      }
+    },
+    "taxonSynonyms": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "taxonCommonNames": {
+      "type": "keyword",
+      "doc_values": true
+    },
+    "taxonComment": {
+      "type": "keyword"
+    },
+    "typeOfGermplasmStorageCode": {
+      "type": "keyword"
+    },
+    "geneticNature": {
+      "type": "keyword"
+    },
+    "comment": {
+      "type": "keyword"
+    },
+    "photo": {
+      "properties": {
+        "file": {
+          "type": "keyword"
+        },
+        "thumbnailFile": {
+          "type": "keyword"
+        },
+        "photoName": {
+          "type": "keyword"
+        },
+        "description": {
+          "type": "keyword"
+        },
+        "copyright": {
+          "type": "keyword"
+        }
+      }
+    },
+    "holdingInstitute": {
+      "properties": {
+        "instituteName": {
+          "type": "keyword"
+        },
+        "instituteCode": {
+          "type": "keyword"
+        },
+        "acronym": {
+          "type": "keyword"
+        },
+        "organisation": {
+          "type": "keyword"
+        },
+        "instituteType": {
+          "type": "keyword"
+        },
+        "webSite": {
+          "type": "keyword"
+        },
+        "address": {
+          "type": "keyword"
+        },
+        "logo": {
+          "type": "keyword"
+        }
+      }
+    },
+    "holdingGenbank": {
+      "properties": {
+        "instituteName": {
+          "type": "keyword",
+          "doc_values": true
+        },
+        "instituteCode": {
+          "type": "keyword"
+        },
+        "webSite": {
+          "type": "keyword"
+        },
+        "logo": {
+          "type": "keyword"
+        }
+      }
+    },
+    "presenceStatus": {
+      "type": "keyword"
+    },
+    "genealogy": {
+      "properties": {
+        "crossingPlan": {
+          "type": "keyword"
+        },
+        "crossingYear": {
+          "type": "keyword"
+        },
+        "familyCode": {
+          "type": "keyword"
+        },
+        "firstParentName": {
+          "type": "keyword"
+        },
+        "firstParentPUI": {
+          "type": "keyword"
+        },
+        "firstParentType": {
+          "type": "keyword"
+        },
+        "secondParentName": {
+          "type": "keyword"
+        },
+        "secondParentPUI": {
+          "type": "keyword"
+        },
+        "secondParentType": {
+          "type": "keyword"
+        },
+        "sibblings": {
+          "properties": {
+            "pui": {
+              "type": "keyword"
+            },
+            "name": {
+              "type": "keyword"
+            }
+          }
+        }
+      }
+    },
+    "children": {
+      "properties": {
+        "firstParentName": {
+          "type": "keyword"
+        },
+        "firstParentPUI": {
+          "type": "keyword"
+        },
+        "secondParentName": {
+          "type": "keyword"
+        },
+        "secondParentPUI": {
+          "type": "keyword"
+        },
+        "sibblings": {
+          "properties": {
+            "pui": {
+              "type": "keyword"
+            },
+            "name": {
+              "type": "keyword"
+            }
+          }
+        }
+      }
+    },
+    "descriptors": {
+      "properties": {
+        "name": {
+          "type": "keyword"
+        },
+        "value": {
+          "type": "keyword"
+        }
+      }
+    },
+    "originSite": {
+      "properties": {
+        "siteId": {
+          "type": "long"
+        },
+        "siteName": {
+          "type": "keyword"
+        },
+        "latitude": {
+          "type": "float"
+        },
+        "longitude": {
+          "type": "float"
+        },
+        "siteType": {
+          "type": "keyword"
+        }
+      }
+    },
+    "collectingSite": {
+      "properties": {
+        "siteId": {
+          "type": "long"
+        },
+        "siteName": {
+          "type": "keyword"
+        },
+        "latitude": {
+          "type": "float"
+        },
+        "longitude": {
+          "type": "float"
+        },
+        "siteType": {
+          "type": "keyword"
+        }
+      }
+    },
+    "evaluationSites": {
+      "properties": {
+        "siteId": {
+          "type": "long"
+        },
+        "siteName": {
+          "type": "keyword"
+        },
+        "latitude": {
+          "type": "float"
+        },
+        "longitude": {
+          "type": "float"
+        },
+        "siteType": {
+          "type": "keyword"
+        }
+      }
+    },
+    "collector": {
+      "properties": {
+        "institute": {
+          "properties": {
+            "instituteName": {
+              "type": "keyword"
+            },
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "address": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
+            }
+          }
+        },
+        "accessionNumber": {
+          "type": "keyword"
+        },
+        "accessionCreationDate": {
+          "type": "integer"
+        },
+        "materialType": {
+          "type": "keyword"
+        },
+        "collectors": {
+          "type": "keyword"
+        }
+      }
+    },
+    "breeder": {
+      "properties": {
+        "institute": {
+          "properties": {
+            "instituteName": {
+              "type": "keyword"
+            },
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "address": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
+            }
+          }
+        },
+        "accessionNumber": {
+          "type": "keyword"
+        },
+        "accessionCreationDate": {
+          "type": "integer"
+        },
+        "registrationYear": {
+          "type": "integer"
+        },
+        "deregistrationYear": {
+          "type": "integer"
+        }
+      }
+    },
+    "distributors": {
+      "properties": {
+        "institute": {
+          "properties": {
+            "instituteName": {
+              "type": "keyword"
+            },
+            "instituteCode": {
+              "type": "keyword"
+            },
+            "acronym": {
+              "type": "keyword"
+            },
+            "organisation": {
+              "type": "keyword"
+            },
+            "instituteType": {
+              "type": "keyword"
+            },
+            "webSite": {
+              "type": "keyword"
+            },
+            "address": {
+              "type": "keyword"
+            },
+            "logo": {
+              "type": "keyword"
+            }
+          }
+        },
+        "accessionNumber": {
+          "type": "keyword"
+        },
+        "distributionStatus": {
+          "type": "keyword"
+        }
+      }
+    },
+    "panel": {
+      "properties": {
+        "id": {
+          "type": "long"
+        },
+        "name": {
+          "type": "keyword",
+          "doc_values": true
+        },
+        "germplasmCount": {
+          "type": "integer"
+        }
+      }
+    },
+    "collection": {
+      "properties": {
+        "id": {
+          "type": "long"
+        },
+        "name": {
+          "type": "keyword",
+          "doc_values": true
+        },
+        "type": {
+          "type": "keyword"
+        },
+        "germplasmCount": {
+          "type": "integer"
+        }
+      }
+    },
+    "population": {
+      "properties": {
+        "id": {
+          "type": "long"
+        },
+        "name": {
+          "type": "keyword",
+          "doc_values": true
+        },
+        "type": {
+          "type": "keyword"
+        },
+        "germplasmRef": {
+          "properties": {
+            "pui": {
+              "type": "keyword"
+            },
+            "name": {
+              "type": "keyword"
+            }
+          }
+        },
+        "germplasmCount": {
+          "type": "integer"
+        }
+      }
+    },
+    "xref": {
+      "properties": {
+        "id": {
+          "type": "keyword"
+        },
+        "source": {
+          "type": "keyword"
+        }
+      }
+    },
+    "additionalInfo": {
+      "dynamic": true,
+      "properties": {}
+    },
+    "studyURIs": {
+      "type": "keyword"
+    },
+    "studyDbIds": {
+      "type": "keyword"
+    },
+    "studyURI": {
+      "type": "keyword"
+    },
+    "studyDbId": {
+      "type": "keyword"
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/location_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/location_mapping.json
index 06aad559d35c1994b73b1bcb52a0dc0e469f24b8..6944c53d0b3f276b57f57559d525d340809ae016 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/location_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/location_mapping.json
@@ -1,94 +1,90 @@
 {
-	"location": {
-		"dynamic": "strict",
-		"properties": {
-			"locationURI": {
-				"type": "keyword"
-			},
-			"locationDbId": {
-				"type": "keyword"
-			},
-			"locationName": {
-				"type": "keyword"
-			},
-			"name": {
-				"type": "keyword"
-			},
-			"abbreviation": {
-				"type": "keyword"
-			},
-			"abreviation": {
-				"type": "keyword"
-			},
-			"locationType": {
-				"type": "keyword"
-			},
-			"type": {
-				"type": "keyword"
-			},
-			"countryCode": {
-				"type": "keyword"
-			},
-			"countryName": {
-				"type": "keyword"
-			},
-			"documentationURL": {
-				"type": "keyword"
-			},
-			"instituteName": {
-				"type": "keyword"
-			},
-			"instituteAddress": {
-				"type": "keyword"
-			},
-			"instituteAdress": {
-				"type": "keyword"
-			},
-			"altitude": {
-				"type": "double"
-			},
-			"latitude": {
-				"type": "double"
-			},
-			"longitude": {
-				"type": "double"
-			},
-			"additionalInfo": {
-				"dynamic": "true",
-				"properties": {}
-			},
-
-			"studyDbIds": {
-				"type": "keyword"
-			},
-			"studyURIs": {
-				"type": "keyword"
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "locationURI": {
+      "type": "keyword"
+    },
+    "locationDbId": {
+      "type": "keyword"
+    },
+    "locationName": {
+      "type": "keyword"
+    },
+    "name": {
+      "type": "keyword"
+    },
+    "abbreviation": {
+      "type": "keyword"
+    },
+    "abreviation": {
+      "type": "keyword"
+    },
+    "locationType": {
+      "type": "keyword"
+    },
+    "type": {
+      "type": "keyword"
+    },
+    "countryCode": {
+      "type": "keyword"
+    },
+    "countryName": {
+      "type": "keyword"
+    },
+    "documentationURL": {
+      "type": "keyword"
+    },
+    "instituteName": {
+      "type": "keyword"
+    },
+    "instituteAddress": {
+      "type": "keyword"
+    },
+    "instituteAdress": {
+      "type": "keyword"
+    },
+    "altitude": {
+      "type": "double"
+    },
+    "latitude": {
+      "type": "double"
+    },
+    "longitude": {
+      "type": "double"
+    },
+    "additionalInfo": {
+      "dynamic": true,
+      "properties": {}
+    },
+    "studyDbIds": {
+      "type": "keyword"
+    },
+    "studyURIs": {
+      "type": "keyword"
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/observationUnit_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/observationUnit_mapping.json
index 5bce2cd447deb3100f170bd0b1acb74cd3385be0..36a02c19506a097d50875c05885e37cee4ced4da 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/observationUnit_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/observationUnit_mapping.json
@@ -1,244 +1,241 @@
 {
-	"observationUnit": {
-		"dynamic": "strict",
-		"properties": {
-			"observationUnitURI": {
-				"type": "keyword"
-			},
-			"observationUnitDbId": {
-				"type": "keyword"
-			},
-			"observationUnitName": {
-				"type": "keyword"
-			},
-			"X": {
-				"type": "keyword"
-			},
-			"Y": {
-				"type": "keyword"
-			},
-			"Xname": {
-				"type": "keyword"
-			},
-			"Yname": {
-				"type": "keyword"
-			},
-			"Xm": {
-				"type": "keyword"
-			},
-			"Ym": {
-				"type": "keyword"
-			},
-			"blockNumber": {
-				"type": "keyword",
-				"index": false
-			},
-			"entryNumber": {
-				"type": "keyword",
-				"index": false
-			},
-			"entryType": {
-				"type": "keyword",
-				"index": false
-			},
-			"germplasmURI": {
-				"type": "keyword"
-			},
-			"germplasmDbId": {
-				"type": "keyword"
-			},
-			"germplasmPUI": {
-				"type": "keyword"
-			},
-			"germplasmName": {
-				"type": "keyword"
-			},
-			"accessionNumber": {
-				"type": "keyword"
-			},
-			"observationLevel": {
-				"type": "keyword"
-			},
-			"observationLevels": {
-				"type": "keyword"
-			},
-			"observationLevelDetails": {
-				"properties": {
-					"type": {
-						"type": "keyword"
-					},
-					"name": {
-						"type": "keyword"
-					},
-					"value": {
-						"type": "keyword"
-					}
-				}
-			},
-			"observationUnitXref": {
-				"properties": {
-					"id": {
-						"type": "keyword"
-					},
-					"source": {
-						"type": "keyword"
-					}
-				}
-			},
-			"observations": {
-				"type": "nested",
-				"properties": {
-					"observationURI": {
-						"type": "keyword"
-					},
-					"observationDbId": {
-						"type": "keyword"
-					},
-					"collector": {
-						"type": "keyword",
-						"index": false
-					},
-					"observationTimeStamp": {
-						"type": "date",
-						"format": "yyyy-MM-dd'T'HH:mm:ss'Z'"
-					},
-					"gdd": {
-						"type": "float"
-					},
-					"observationVariableURI": {
-						"type": "keyword"
-					},
-					"observationVariableDbId": {
-						"type": "keyword"
-					},
-					"observationVariableName": {
-						"type": "keyword"
-					},
-					"specificName": {
-						"type": "keyword"
-					},
-					"season": {
-						"type": "keyword"
-					},
-					"value": {
-						"type": "keyword"
-					},
-					"isDataFile": {
-						"type": "boolean",
-						"index": false
-					}
-				}
-			},
-			"plantNumber": {
-				"type": "keyword",
-				"index": false
-			},
-			"plotNumber": {
-				"type": "keyword",
-				"index": false
-			},
-			"programURI": {
-				"type": "keyword"
-			},
-			"programDbId": {
-				"type": "keyword"
-			},
-			"programName": {
-				"type": "keyword"
-			},
-			"replicate": {
-				"type": "keyword",
-				"index": false
-			},
-			"studyURI": {
-				"type": "keyword"
-			},
-			"studyDbId": {
-				"type": "keyword"
-			},
-			"studyName": {
-				"type": "keyword"
-			},
-			"studyLocationURI": {
-				"type": "keyword"
-			},
-			"studyLocationDbId": {
-				"type": "keyword"
-			},
-			"studyLocation": {
-				"type": "keyword"
-			},
-			"treatments": {
-				"properties": {
-					"factor": {
-						"type": "keyword"
-					},
-					"modality": {
-						"type": "keyword"
-					}
-				}
-			},
-			"trials": {
-				"properties": {
-					"id": {
-						"type": "long"
-					},
-					"name": {
-						"type": "keyword"
-					}
-				}
-			},
-			"taxonScientificName": {
-				"type": "keyword"
-			},
-			"germplasmGenus": {
-				"type": "keyword"
-			},
-			"germplasmCollections": {
-				"properties": {
-					"id": {
-						"type": "long"
-					},
-					"name": {
-						"type": "keyword"
-					}
-				}
-			},
-			"germplasmPanels": {
-				"properties": {
-					"id": {
-						"type": "long"
-					},
-					"name": {
-						"type": "keyword"
-					}
-				}
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": "strict",
+  "properties": {
+    "observationUnitURI": {
+      "type": "keyword"
+    },
+    "observationUnitDbId": {
+      "type": "keyword"
+    },
+    "observationUnitName": {
+      "type": "keyword"
+    },
+    "X": {
+      "type": "keyword"
+    },
+    "Y": {
+      "type": "keyword"
+    },
+    "Xname": {
+      "type": "keyword"
+    },
+    "Yname": {
+      "type": "keyword"
+    },
+    "Xm": {
+      "type": "keyword"
+    },
+    "Ym": {
+      "type": "keyword"
+    },
+    "blockNumber": {
+      "type": "keyword",
+      "index": false
+    },
+    "entryNumber": {
+      "type": "keyword",
+      "index": false
+    },
+    "entryType": {
+      "type": "keyword",
+      "index": false
+    },
+    "germplasmURI": {
+      "type": "keyword"
+    },
+    "germplasmDbId": {
+      "type": "keyword"
+    },
+    "germplasmPUI": {
+      "type": "keyword"
+    },
+    "germplasmName": {
+      "type": "keyword"
+    },
+    "accessionNumber": {
+      "type": "keyword"
+    },
+    "observationLevel": {
+      "type": "keyword"
+    },
+    "observationLevels": {
+      "type": "keyword"
+    },
+    "observationLevelDetails": {
+      "properties": {
+        "type": {
+          "type": "keyword"
+        },
+        "name": {
+          "type": "keyword"
+        },
+        "value": {
+          "type": "keyword"
+        }
+      }
+    },
+    "observationUnitXref": {
+      "properties": {
+        "id": {
+          "type": "keyword"
+        },
+        "source": {
+          "type": "keyword"
+        }
+      }
+    },
+    "observations": {
+      "type": "nested",
+      "properties": {
+        "observationURI": {
+          "type": "keyword"
+        },
+        "observationDbId": {
+          "type": "keyword"
+        },
+        "collector": {
+          "type": "keyword",
+          "index": false
+        },
+        "observationTimeStamp": {
+          "type": "date",
+          "format": "yyyy-MM-dd'T'HH:mm:ss'Z'"
+        },
+        "gdd": {
+          "type": "float"
+        },
+        "observationVariableURI": {
+          "type": "keyword"
+        },
+        "observationVariableDbId": {
+          "type": "keyword"
+        },
+        "observationVariableName": {
+          "type": "keyword"
+        },
+        "specificName": {
+          "type": "keyword"
+        },
+        "season": {
+          "type": "keyword"
+        },
+        "value": {
+          "type": "keyword"
+        },
+        "isDataFile": {
+          "type": "boolean",
+          "index": false
+        }
+      }
+    },
+    "plantNumber": {
+      "type": "keyword",
+      "index": false
+    },
+    "plotNumber": {
+      "type": "keyword",
+      "index": false
+    },
+    "programURI": {
+      "type": "keyword"
+    },
+    "programDbId": {
+      "type": "keyword"
+    },
+    "programName": {
+      "type": "keyword"
+    },
+    "replicate": {
+      "type": "keyword",
+      "index": false
+    },
+    "studyURI": {
+      "type": "keyword"
+    },
+    "studyDbId": {
+      "type": "keyword"
+    },
+    "studyName": {
+      "type": "keyword"
+    },
+    "studyLocationURI": {
+      "type": "keyword"
+    },
+    "studyLocationDbId": {
+      "type": "keyword"
+    },
+    "studyLocation": {
+      "type": "keyword"
+    },
+    "treatments": {
+      "properties": {
+        "factor": {
+          "type": "keyword"
+        },
+        "modality": {
+          "type": "keyword"
+        }
+      }
+    },
+    "trials": {
+      "properties": {
+        "id": {
+          "type": "long"
+        },
+        "name": {
+          "type": "keyword"
+        }
+      }
+    },
+    "taxonScientificName": {
+      "type": "keyword"
+    },
+    "germplasmGenus": {
+      "type": "keyword"
+    },
+    "germplasmCollections": {
+      "properties": {
+        "id": {
+          "type": "long"
+        },
+        "name": {
+          "type": "keyword"
+        }
+      }
+    },
+    "germplasmPanels": {
+      "properties": {
+        "id": {
+          "type": "long"
+        },
+        "name": {
+          "type": "keyword"
+        }
+      }
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/program_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/program_mapping.json
index abd710be92a05aafcddf83272895aa94d07d006a..83b07c0d5a4430bccac85d382c37a8a363ab0b27 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/program_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/program_mapping.json
@@ -1,78 +1,74 @@
 {
-	"program": {
-		"dynamic": "strict",
-		"properties": {
-			"programURI": {
-				"type": "keyword"
-			},
-			"programDbId": {
-				"type": "keyword"
-			},
-			"programName": {
-				"type": "keyword"
-			},
-			"name": {
-				"type": "keyword"
-			},
-			"abbreviation": {
-				"type": "keyword"
-			},
-			"commonCropName": {
-				"type": "keyword"
-			},
-			"documentationURL": {
-				"type": "keyword"
-			},
-			"leadPerson": {
-				"type": "keyword"
-			},
-			"leadPersonDbId": {
-				"type": "keyword"
-			},
-			"leadPersonName": {
-				"type": "keyword"
-			},
-			"objective": {
-				"type": "keyword"
-			},
-
-			"trialDbIds": {
-				"type": "keyword"
-			},
-			"trialURIs": {
-				"type": "keyword"
-			},
-			"studyDbIds": {
-				"type": "keyword"
-			},
-			"studyURIs": {
-				"type": "keyword"
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "programURI": {
+      "type": "keyword"
+    },
+    "programDbId": {
+      "type": "keyword"
+    },
+    "programName": {
+      "type": "keyword"
+    },
+    "name": {
+      "type": "keyword"
+    },
+    "abbreviation": {
+      "type": "keyword"
+    },
+    "commonCropName": {
+      "type": "keyword"
+    },
+    "documentationURL": {
+      "type": "keyword"
+    },
+    "leadPerson": {
+      "type": "keyword"
+    },
+    "leadPersonDbId": {
+      "type": "keyword"
+    },
+    "leadPersonName": {
+      "type": "keyword"
+    },
+    "objective": {
+      "type": "keyword"
+    },
+    "trialDbIds": {
+      "type": "keyword"
+    },
+    "trialURIs": {
+      "type": "keyword"
+    },
+    "studyDbIds": {
+      "type": "keyword"
+    },
+    "studyURIs": {
+      "type": "keyword"
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json
index db9668c85c563b29b19c16aa5b65d9969ae5a3b1..c4cef5da29524b7efab7d8a46edbd1a3f6cb3f2b 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/settings.json
@@ -5,7 +5,7 @@
 	"analysis": {
 		"filter": {
 			"1-20-edgeNGram": {
-				"type": "edgeNGram",
+				"type": "edge_ngram",
 				"side": "front",
 				"min_gram": 1,
 				"max_gram": 20
@@ -22,7 +22,6 @@
 				"type": "custom",
 				"tokenizer": "special_tokenizer",
 				"filter": [
-					"standard",
 					"lowercase",
 					"asciifolding"
 				]
@@ -31,7 +30,6 @@
 				"type": "custom",
 				"tokenizer": "special_tokenizer",
 				"filter": [
-					"standard",
 					"lowercase",
 					"asciifolding",
 					"1-20-edgeNGram"
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/study_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/study_mapping.json
index ea2a7e22c3449595e0957cc812be2051d3dc37d2..5acc5504f528e4c01b6ccf0299b4629e72e460c9 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/study_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/study_mapping.json
@@ -1,275 +1,272 @@
 {
-	"study": {
-		"dynamic": "strict",
-		"properties": {
-			"studyURI": {
-				"type": "keyword"
-			},
-			"studyDbId": {
-				"type": "keyword"
-			},
-			"studyName": {
-				"type": "keyword"
-			},
-			"name": {
-				"type": "keyword"
-			},
-			"active": {
-				"type": "boolean"
-			},
-			"commonCropName": {
-				"type": "keyword"
-			},
-			"cropDbId": {
-                                "type": "keyword"
-                        },
-			"statisticalDesign": {
-				"dynamic": "true",
-				"properties": {}
-                        },
-			"description": {
-                                "type": "keyword"
-                        },
-			"organism": {
-				"type": "keyword"
-			},
-			"contactURIs": {
-				"type": "keyword"
-			},
-			"contactDbIds": {
-				"type": "keyword"
-			},
-			"contacts": {
-				"properties": {
-					"contactURI": {
-						"type": "keyword"
-					},
-					"contactDbId": {
-						"type": "keyword"
-					},
-					"name": {
-						"type": "keyword"
-					},
-					"instituteName": {
-						"type": "keyword"
-					},
-					"email": {
-						"type": "keyword"
-					},
-					"type": {
-						"type": "keyword"
-					},
-					"orcid": {
-						"type": "keyword"
-					}
-				}
-			},
-			"dataLinks": {
-				"properties": {
-					"dataLinkName": {
-						"type": "keyword"
-					},
-					"name": {
-						"type": "keyword"
-					},
-					"type": {
-						"type": "keyword"
-					},
-					"url": {
-						"type": "keyword"
-					}
-				}
-			},
-			"documentationURL": {
-				"type": "keyword"
-			},
-			"startDate": {
-				"type": "date",
-				"format": "YYYY-MM-dd"
-			},
-			"endDate": {
-				"type": "date",
-				"format": "YYYY-MM-dd"
-			},
-			"year": {
-				"type": "keyword"
-			},
-			"lastUpdate": {
-				"properties": {
-					"version": {
-						"type": "keyword"
-					},
-					"timestamp": {
-						"type": "date",
-						"format": "yyyy-MM-dd||yyyy-MM-dd'T'HH:mm:ss'Z'"
-					}
-				}
-			},
-			"license": {
-				"type": "keyword"
-			},
-			"locationURIs": {
-				"type": "keyword"
-			},
-			"locationDbIds": {
-				"type": "keyword"
-			},
-			"locationURI": {
-				"type": "keyword"
-			},
-			"locationDbId": {
-				"type": "keyword"
-			},
-			"locationName": {
-				"type": "keyword"
-			},
-			"location": {
-				"properties": {
-					"locationURI": {
-						"type": "keyword"
-					},
-					"locationDbId": {
-						"type": "keyword"
-					},
-					"locationName": {
-						"type": "keyword"
-					},
-					"name": {
-						"type": "keyword"
-					},
-					"abbreviation": {
-						"type": "keyword"
-					},
-					"abreviation": {
-						"type": "keyword"
-					},
-					"locationType": {
-						"type": "keyword"
-					},
-					"countryCode": {
-						"type": "keyword"
-					},
-					"countryName": {
-						"type": "keyword"
-					},
-					"documentationURL": {
-						"type": "keyword"
-					},
-					"instituteName": {
-						"type": "keyword"
-					},
-					"instituteAddress": {
-						"type": "keyword"
-					},
-					"instituteAdress": {
-						"type": "keyword"
-					},
-					"altitude": {
-						"type": "double"
-					},
-					"latitude": {
-						"type": "double"
-					},
-					"longitude": {
-						"type": "double"
-					},
-					"additionalInfo": {
-						"dynamic": "true",
-						"type": "object",
-						"properties": {}
-					}
-				}
-			},
-			"programURIs": {
-				"type": "keyword"
-			},
-			"programDbIds": {
-				"type": "keyword"
-			},
-			"programURI": {
-				"type": "keyword"
-			},
-			"programDbId": {
-				"type": "keyword"
-			},
-			"programName": {
-				"type": "keyword"
-			},
-			"seasons": {
-				"type": "keyword"
-			},
-			"studyDescription": {
-				"type": "keyword"
-			},
-			"studyTypeURI": {
-				"type": "keyword"
-			},
-			"studyTypeDbId": {
-				"type": "keyword"
-			},
-			"studyType": {
-				"type": "keyword"
-			},
-			"studyTypeName": {
-				"type": "keyword"
-			},
-			"trialURIs": {
-				"type": "keyword"
-			},
-			"trialDbIds": {
-				"type": "keyword"
-			},
-			"trialURI": {
-				"type": "keyword"
-			},
-			"trialDbId": {
-				"type": "keyword"
-			},
-			"trialName": {
-				"type": "keyword"
-			},
-			"germplasmURIs": {
-				"type": "keyword"
-			},
-			"germplasmDbIds": {
-				"type": "keyword"
-			},
-			"observationVariableURIs": {
-				"type": "keyword"
-			},
-			"observationVariableDbIds": {
-				"type": "keyword"
-			},
-			"additionalInfo": {
-				"dynamic": "true",
-				"type": "object",
-				"properties": {}
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "studyURI": {
+      "type": "keyword"
+    },
+    "studyDbId": {
+      "type": "keyword"
+    },
+    "studyName": {
+      "type": "keyword"
+    },
+    "name": {
+      "type": "keyword"
+    },
+    "active": {
+      "type": "boolean"
+    },
+    "commonCropName": {
+      "type": "keyword"
+    },
+    "cropDbId": {
+      "type": "keyword"
+    },
+    "statisticalDesign": {
+      "dynamic": true,
+      "properties": {}
+    },
+    "description": {
+      "type": "keyword"
+    },
+    "organism": {
+      "type": "keyword"
+    },
+    "contactURIs": {
+      "type": "keyword"
+    },
+    "contactDbIds": {
+      "type": "keyword"
+    },
+    "contacts": {
+      "properties": {
+        "contactURI": {
+          "type": "keyword"
+        },
+        "contactDbId": {
+          "type": "keyword"
+        },
+        "name": {
+          "type": "keyword"
+        },
+        "instituteName": {
+          "type": "keyword"
+        },
+        "email": {
+          "type": "keyword"
+        },
+        "type": {
+          "type": "keyword"
+        },
+        "orcid": {
+          "type": "keyword"
+        }
+      }
+    },
+    "dataLinks": {
+      "properties": {
+        "dataLinkName": {
+          "type": "keyword"
+        },
+        "name": {
+          "type": "keyword"
+        },
+        "type": {
+          "type": "keyword"
+        },
+        "url": {
+          "type": "keyword"
+        }
+      }
+    },
+    "documentationURL": {
+      "type": "keyword"
+    },
+    "startDate": {
+      "type": "date",
+      "format": "YYYY-MM-dd"
+    },
+    "endDate": {
+      "type": "date",
+      "format": "YYYY-MM-dd"
+    },
+    "year": {
+      "type": "keyword"
+    },
+    "lastUpdate": {
+      "properties": {
+        "version": {
+          "type": "keyword"
+        },
+        "timestamp": {
+          "type": "date",
+          "format": "yyyy-MM-dd||yyyy-MM-dd'T'HH:mm:ss'Z'"
+        }
+      }
+    },
+    "license": {
+      "type": "keyword"
+    },
+    "locationURIs": {
+      "type": "keyword"
+    },
+    "locationDbIds": {
+      "type": "keyword"
+    },
+    "locationURI": {
+      "type": "keyword"
+    },
+    "locationDbId": {
+      "type": "keyword"
+    },
+    "locationName": {
+      "type": "keyword"
+    },
+    "location": {
+      "properties": {
+        "locationURI": {
+          "type": "keyword"
+        },
+        "locationDbId": {
+          "type": "keyword"
+        },
+        "locationName": {
+          "type": "keyword"
+        },
+        "name": {
+          "type": "keyword"
+        },
+        "abbreviation": {
+          "type": "keyword"
+        },
+        "abreviation": {
+          "type": "keyword"
+        },
+        "locationType": {
+          "type": "keyword"
+        },
+        "countryCode": {
+          "type": "keyword"
+        },
+        "countryName": {
+          "type": "keyword"
+        },
+        "documentationURL": {
+          "type": "keyword"
+        },
+        "instituteName": {
+          "type": "keyword"
+        },
+        "instituteAddress": {
+          "type": "keyword"
+        },
+        "instituteAdress": {
+          "type": "keyword"
+        },
+        "altitude": {
+          "type": "double"
+        },
+        "latitude": {
+          "type": "double"
+        },
+        "longitude": {
+          "type": "double"
+        },
+        "additionalInfo": {
+          "dynamic": true,
+          "type": "object",
+          "properties": {}
+        }
+      }
+    },
+    "programURIs": {
+      "type": "keyword"
+    },
+    "programDbIds": {
+      "type": "keyword"
+    },
+    "programURI": {
+      "type": "keyword"
+    },
+    "programDbId": {
+      "type": "keyword"
+    },
+    "programName": {
+      "type": "keyword"
+    },
+    "seasons": {
+      "type": "keyword"
+    },
+    "studyDescription": {
+      "type": "keyword"
+    },
+    "studyTypeURI": {
+      "type": "keyword"
+    },
+    "studyTypeDbId": {
+      "type": "keyword"
+    },
+    "studyType": {
+      "type": "keyword"
+    },
+    "studyTypeName": {
+      "type": "keyword"
+    },
+    "trialURIs": {
+      "type": "keyword"
+    },
+    "trialDbIds": {
+      "type": "keyword"
+    },
+    "trialURI": {
+      "type": "keyword"
+    },
+    "trialDbId": {
+      "type": "keyword"
+    },
+    "trialName": {
+      "type": "keyword"
+    },
+    "germplasmURIs": {
+      "type": "keyword"
+    },
+    "germplasmDbIds": {
+      "type": "keyword"
+    },
+    "observationVariableURIs": {
+      "type": "keyword"
+    },
+    "observationVariableDbIds": {
+      "type": "keyword"
+    },
+    "additionalInfo": {
+      "dynamic": true,
+      "type": "object",
+      "properties": {}
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/transplant_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/transplant_mapping.json
deleted file mode 100644
index 5aec114caea1a5828d00461d3ce98b73ce4921e0..0000000000000000000000000000000000000000
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/transplant_mapping.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-	"transplant": {
-		"dynamic": "true",
-		"properties": {
-			"entry_type": {
-				"type": "keyword"
-			},
-			"linkedRessourcesID": {
-				"type": "keyword"
-			}
-		}
-	}
-}
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/trial_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/trial_mapping.json
index 3793e3f8d9f6ae182cba6aa2ee70fc48b65487b1..f433ebb70ad1fc00d769cbb9a637cfab6c6e2606 100644
--- a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/trial_mapping.json
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/trial_mapping.json
@@ -1,362 +1,357 @@
 {
-	"trial": {
-		"dynamic": "strict",
-		"properties": {
-			"trialURI": {
-				"type": "keyword"
-			},
-			"trialDbId": {
-				"type": "keyword"
-			},
-			"trialName": {
-				"type": "keyword"
-			},
-			"trialPUI": {
-				"type": "keyword"
-			},
-			"trialType": {
-				"type": "keyword"
-			},
-			"active": {
-				"type": "boolean"
-			},
-			"commonCropName": {
-				"type": "keyword"
-			},
-			"cropDbId": {
-				"type": "keyword"
-			},
-			"trialDescription": {
-				"type": "keyword"
-			},
-			"documentationURL": {
-				"type": "keyword"
-			},
-			"startDate": {
-				"type": "date",
-				"format": "YYYY-MM-dd"
-			},
-			"endDate": {
-				"type": "date",
-				"format": "YYYY-MM-dd"
-			},
-			"publications": {
-				"properties": {
-					"publicationReference": {
-						"type": "keyword"
-					},
-					"publicationPUI": {
-						"type": "keyword"
-					}
-				}
-			},
-			"programURIs": {
-				"type": "keyword"
-			},
-			"programDbIds": {
-				"type": "keyword"
-			},
-			"programURI": {
-				"type": "keyword"
-			},
-			"programDbId": {
-				"type": "keyword"
-			},
-			"programName": {
-				"type": "keyword"
-			},
-			"studyURIs": {
-				"type": "keyword"
-			},
-			"studyDbIds": {
-				"type": "keyword"
-			},
-			"studies": {
-				"properties": {
-					"studyURI": {
-						"type": "keyword"
-					},
-					"studyDbId": {
-						"type": "keyword"
-					},
-					"studyName": {
-						"type": "keyword"
-					},
-					"name": {
-						"type": "keyword"
-					},
-					"studyDescription": {
-						"type": "keyword"
-					},
-					"description": {
-                                                "type": "keyword"
-                                        },
-					"locationURI": {
-						"type": "keyword"
-					},
-					"locationDbId": {
-						"type": "keyword"
-					},
-					"locationName": {
-						"type": "keyword"
-					},
-					"active": {
-						"type": "boolean"
-					},
-					"commonCropName": {
-						"type": "keyword"
-					},
-					"cropDbId": {
-						"type": "keyword"
-					},
-					"contactURIs": {
-						"type": "keyword"
-					},
-					"contactDbIds": {
-						"type": "keyword"
-					},
-					"dataLinks": {
-						"properties": {
-							"name": {
-								"type": "keyword"
-							},
-							"type": {
-								"type": "keyword"
-							},
-							"url": {
-								"type": "keyword"
-							}
-						}
-					},
-					"documentationURL": {
-						"type": "keyword"
-					},
-					"startDate": {
-						"type": "date",
-						"format": "YYYY-MM-dd"
-					},
-					"endDate": {
-						"type": "date",
-						"format": "YYYY-MM-dd"
-					},
-					"lastUpdate": {
-                                                "dynamic": "true",
-                                                "properties": {}
-					},
-					"license": {
-						"type": "keyword"
-					},
-					"programURIs": {
-						"type": "keyword"
-					},
-					"programDbIds": {
-						"type": "keyword"
-					},
-					"programURI": {
-						"type": "keyword"
-					},
-					"programDbId": {
-						"type": "keyword"
-					},
-					"programName": {
-						"type": "keyword"
-					},
-					"seasons": {
-						"dynamic": "true",
-						"properties": {}
-					},
-					"studyType": {
-						"type": "keyword"
-					},
-					"studyTypeName": {
-						"type": "keyword"
-					},
-					"trialURIs": {
-						"type": "keyword"
-					},
-					"trialDbIds": {
-						"type": "keyword"
-					},
-					"trialURI": {
-						"type": "keyword"
-					},
-					"trialDbId": {
-						"type": "keyword"
-					},
-					"trialName": {
-						"type": "keyword"
-					},
-					"germplasmURIs": {
-						"type": "keyword"
-					},
-					"germplasmDbIds": {
-						"type": "keyword"
-					},
-					"observationVariableURIs": {
-						"type": "keyword"
-					},
-					"observationVariableDbIds": {
-						"type": "keyword"
-					},
-					"locationURIs": {
-						"type": "keyword"
-					},
-					"locationDbIds": {
-						"type": "keyword"
-					},
-					"additionalInfo": {
-						"dynamic": "true",
-						"type": "object",
-						"properties": {}
-					},
-
-					"source": {
-						"type": "keyword"
-					},
-					"groupId": {
-						"type": "long"
-					},
-					"@type": {
-						"type": "keyword"
-					},
-					"@id": {
-						"type": "keyword"
-					},
-					"schema:includedInDataCatalog": {
-						"type": "keyword"
-					},
-					"schema:identifier": {
-						"type": "keyword"
-					},
-					"schema:name": {
-						"type": "keyword"
-					},
-					"schema:url": {
-						"type": "keyword"
-					}
-				}
-			},
-			"datasetAuthorship": {
-				"properties": {
-					"license": {
-						"type": "keyword"
-					},
-					"datasetPUI": {
-						"type": "keyword"
-					}
-				}
-			},
-			"datasetAuthorships": {
-				"properties": {
-					"license": {
-						"type": "keyword"
-					},
-					"datasetPUI": {
-						"type": "keyword"
-					}
-				}
-			},
-			"contactURIs": {
-				"type": "keyword"
-			},
-			"contactDbIds": {
-				"type": "keyword"
-			},
-			"contacts": {
-				"properties": {
-					"contactURI": {
-						"type": "keyword"
-					},
-					"contactDbId": {
-						"type": "keyword"
-					},
-					"name": {
-						"type": "keyword"
-					},
-					"instituteName": {
-						"type": "keyword"
-					},
-          "institutionName": {
-						"type": "keyword"
-					},
-					"email": {
-						"type": "keyword"
-					},
-					"type": {
-						"type": "keyword"
-					},
-					"orcid": {
-						"type": "keyword"
-					},
-					"studyURIs": {
-						"type": "keyword"
-					},
-					"studyDbIds": {
-						"type": "keyword"
-					},
-					"trialURIs": {
-						"type": "keyword"
-					},
-					"trialDbIds": {
-						"type": "keyword"
-					},
-
-					"source": {
-						"type": "keyword"
-					},
-					"groupId": {
-						"type": "long"
-					},
-					"@type": {
-						"type": "keyword"
-					},
-					"@id": {
-						"type": "keyword"
-					},
-					"schema:includedInDataCatalog": {
-						"type": "keyword"
-					},
-					"schema:identifier": {
-						"type": "keyword"
-					},
-					"schema:name": {
-						"type": "keyword"
-					},
-					"schema:url": {
-						"type": "keyword"
-					}
-				}
-			},
-			"additionalInfo": {
-				"dynamic": "true",
-				"type": "object",
-				"properties": {}
-			},
-
-			"source": {
-				"type": "keyword"
-			},
-			"groupId": {
-				"type": "long"
-			},
-			"@type": {
-				"type": "keyword"
-			},
-			"@id": {
-				"type": "keyword"
-			},
-			"schema:includedInDataCatalog": {
-				"type": "keyword"
-			},
-			"schema:identifier": {
-				"type": "keyword"
-			},
-			"schema:name": {
-				"type": "keyword"
-			},
-			"schema:url": {
-				"type": "keyword"
-			}
-		}
-	}
+  "dynamic": false,
+  "properties": {
+    "trialURI": {
+      "type": "keyword"
+    },
+    "trialDbId": {
+      "type": "keyword"
+    },
+    "trialName": {
+      "type": "keyword"
+    },
+    "trialPUI": {
+      "type": "keyword"
+    },
+    "trialType": {
+      "type": "keyword"
+    },
+    "active": {
+      "type": "boolean"
+    },
+    "commonCropName": {
+      "type": "keyword"
+    },
+    "cropDbId": {
+      "type": "keyword"
+    },
+    "trialDescription": {
+      "type": "keyword"
+    },
+    "documentationURL": {
+      "type": "keyword"
+    },
+    "startDate": {
+      "type": "date",
+      "format": "YYYY-MM-dd"
+    },
+    "endDate": {
+      "type": "date",
+      "format": "YYYY-MM-dd"
+    },
+    "publications": {
+      "properties": {
+        "publicationReference": {
+          "type": "keyword"
+        },
+        "publicationPUI": {
+          "type": "keyword"
+        }
+      }
+    },
+    "programURIs": {
+      "type": "keyword"
+    },
+    "programDbIds": {
+      "type": "keyword"
+    },
+    "programURI": {
+      "type": "keyword"
+    },
+    "programDbId": {
+      "type": "keyword"
+    },
+    "programName": {
+      "type": "keyword"
+    },
+    "studyURIs": {
+      "type": "keyword"
+    },
+    "studyDbIds": {
+      "type": "keyword"
+    },
+    "studies": {
+      "properties": {
+        "studyURI": {
+          "type": "keyword"
+        },
+        "studyDbId": {
+          "type": "keyword"
+        },
+        "studyName": {
+          "type": "keyword"
+        },
+        "name": {
+          "type": "keyword"
+        },
+        "studyDescription": {
+          "type": "keyword"
+        },
+        "description": {
+          "type": "keyword"
+        },
+        "locationURI": {
+          "type": "keyword"
+        },
+        "locationDbId": {
+          "type": "keyword"
+        },
+        "locationName": {
+          "type": "keyword"
+        },
+        "active": {
+          "type": "boolean"
+        },
+        "commonCropName": {
+          "type": "keyword"
+        },
+        "cropDbId": {
+          "type": "keyword"
+        },
+        "contactURIs": {
+          "type": "keyword"
+        },
+        "contactDbIds": {
+          "type": "keyword"
+        },
+        "dataLinks": {
+          "properties": {
+            "name": {
+              "type": "keyword"
+            },
+            "type": {
+              "type": "keyword"
+            },
+            "url": {
+              "type": "keyword"
+            }
+          }
+        },
+        "documentationURL": {
+          "type": "keyword"
+        },
+        "startDate": {
+          "type": "date",
+          "format": "YYYY-MM-dd"
+        },
+        "endDate": {
+          "type": "date",
+          "format": "YYYY-MM-dd"
+        },
+        "lastUpdate": {
+          "dynamic": true,
+          "properties": {}
+        },
+        "license": {
+          "type": "keyword"
+        },
+        "programURIs": {
+          "type": "keyword"
+        },
+        "programDbIds": {
+          "type": "keyword"
+        },
+        "programURI": {
+          "type": "keyword"
+        },
+        "programDbId": {
+          "type": "keyword"
+        },
+        "programName": {
+          "type": "keyword"
+        },
+        "seasons": {
+          "dynamic": true,
+          "properties": {}
+        },
+        "studyType": {
+          "type": "keyword"
+        },
+        "studyTypeName": {
+          "type": "keyword"
+        },
+        "trialURIs": {
+          "type": "keyword"
+        },
+        "trialDbIds": {
+          "type": "keyword"
+        },
+        "trialURI": {
+          "type": "keyword"
+        },
+        "trialDbId": {
+          "type": "keyword"
+        },
+        "trialName": {
+          "type": "keyword"
+        },
+        "germplasmURIs": {
+          "type": "keyword"
+        },
+        "germplasmDbIds": {
+          "type": "keyword"
+        },
+        "observationVariableURIs": {
+          "type": "keyword"
+        },
+        "observationVariableDbIds": {
+          "type": "keyword"
+        },
+        "locationURIs": {
+          "type": "keyword"
+        },
+        "locationDbIds": {
+          "type": "keyword"
+        },
+        "additionalInfo": {
+          "dynamic": true,
+          "type": "object",
+          "properties": {}
+        },
+        "source": {
+          "type": "keyword"
+        },
+        "groupId": {
+          "type": "long"
+        },
+        "@type": {
+          "type": "keyword"
+        },
+        "@id": {
+          "type": "keyword"
+        },
+        "schema:includedInDataCatalog": {
+          "type": "keyword"
+        },
+        "schema:identifier": {
+          "type": "keyword"
+        },
+        "schema:name": {
+          "type": "keyword"
+        },
+        "schema:url": {
+          "type": "keyword"
+        }
+      }
+    },
+    "datasetAuthorship": {
+      "properties": {
+        "license": {
+          "type": "keyword"
+        },
+        "datasetPUI": {
+          "type": "keyword"
+        }
+      }
+    },
+    "datasetAuthorships": {
+      "properties": {
+        "license": {
+          "type": "keyword"
+        },
+        "datasetPUI": {
+          "type": "keyword"
+        }
+      }
+    },
+    "contactURIs": {
+      "type": "keyword"
+    },
+    "contactDbIds": {
+      "type": "keyword"
+    },
+    "contacts": {
+      "properties": {
+        "contactURI": {
+          "type": "keyword"
+        },
+        "contactDbId": {
+          "type": "keyword"
+        },
+        "name": {
+          "type": "keyword"
+        },
+        "instituteName": {
+          "type": "keyword"
+        },
+        "institutionName": {
+          "type": "keyword"
+        },
+        "email": {
+          "type": "keyword"
+        },
+        "type": {
+          "type": "keyword"
+        },
+        "orcid": {
+          "type": "keyword"
+        },
+        "studyURIs": {
+          "type": "keyword"
+        },
+        "studyDbIds": {
+          "type": "keyword"
+        },
+        "trialURIs": {
+          "type": "keyword"
+        },
+        "trialDbIds": {
+          "type": "keyword"
+        },
+        "source": {
+          "type": "keyword"
+        },
+        "groupId": {
+          "type": "long"
+        },
+        "@type": {
+          "type": "keyword"
+        },
+        "@id": {
+          "type": "keyword"
+        },
+        "schema:includedInDataCatalog": {
+          "type": "keyword"
+        },
+        "schema:identifier": {
+          "type": "keyword"
+        },
+        "schema:name": {
+          "type": "keyword"
+        },
+        "schema:url": {
+          "type": "keyword"
+        }
+      }
+    },
+    "additionalInfo": {
+      "dynamic": true,
+      "type": "object",
+      "properties": {}
+    },
+    "source": {
+      "type": "keyword"
+    },
+    "groupId": {
+      "type": "long"
+    },
+    "@type": {
+      "type": "keyword"
+    },
+    "@id": {
+      "type": "keyword"
+    },
+    "schema:includedInDataCatalog": {
+      "type": "keyword"
+    },
+    "schema:identifier": {
+      "type": "keyword"
+    },
+    "schema:name": {
+      "type": "keyword"
+    },
+    "schema:url": {
+      "type": "keyword"
+    }
+  }
 }
diff --git a/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/xref_mapping.json b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/xref_mapping.json
new file mode 100644
index 0000000000000000000000000000000000000000..f7a05def483a981c7de315ccc0ef7fe3c90f6835
--- /dev/null
+++ b/backend/src/test/resources/fr/inra/urgi/faidare/repository/es/setup/index/xref_mapping.json
@@ -0,0 +1,11 @@
+{
+  "dynamic": "true",
+  "properties": {
+    "entryType": {
+      "type": "keyword"
+    },
+    "linkedResourcesID": {
+      "type": "keyword"
+    }
+  }
+}
diff --git a/backend/src/test/resources/test.properties b/backend/src/test/resources/test.properties
index a82442ba931e528774043a0ed48bbb38de4efa70..fae763c68b5272818217300769fb71ec32205506 100644
--- a/backend/src/test/resources/test.properties
+++ b/backend/src/test/resources/test.properties
@@ -1,5 +1,2 @@
-spring.data.elasticsearch.host=localhost
-spring.data.elasticsearch.port=9200
-
 faidare.elasticsearch-alias-template=gnpis_{source}_{documentType}-group{groupId}
 faidare.elasticsearch-xref-index-name=urgi_xref_test
diff --git a/backend/src/test/test.iml b/backend/src/test/test.iml
deleted file mode 100644
index 6e30bb1c6134aa08b8bcfb9660df0484e83585c6..0000000000000000000000000000000000000000
--- a/backend/src/test/test.iml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="true" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="main" />
-  </component>
-</module>
diff --git a/data/test/json-bulk/IBET/contact-1.json.gz b/data/test/json-bulk/IBET/contact-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..c1b6344d87f355632599e1831f0a1ee2ecfbed96
Binary files /dev/null and b/data/test/json-bulk/IBET/contact-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/datadiscovery-1.json.gz b/data/test/json-bulk/IBET/datadiscovery-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..0d669f734808c661111fad31b36089aefcb7e645
Binary files /dev/null and b/data/test/json-bulk/IBET/datadiscovery-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/germplasm-1.json.gz b/data/test/json-bulk/IBET/germplasm-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..1beb30992239f61e986a7d0dbe8b6ad38aa10090
Binary files /dev/null and b/data/test/json-bulk/IBET/germplasm-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/location-1.json.gz b/data/test/json-bulk/IBET/location-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..3641132aa4ab7ff200b32cd1d39ec55a41435877
Binary files /dev/null and b/data/test/json-bulk/IBET/location-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/observationVariable-1.json.gz b/data/test/json-bulk/IBET/observationVariable-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2e6894648f30de88989ee0061d5b3eed3b685a80
Binary files /dev/null and b/data/test/json-bulk/IBET/observationVariable-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/ontology-1.json.gz b/data/test/json-bulk/IBET/ontology-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..fb6947bb15fcf5ec5eba045523d6da8f414fab1a
Binary files /dev/null and b/data/test/json-bulk/IBET/ontology-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/program-1.json.gz b/data/test/json-bulk/IBET/program-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..66c4d54d549c33558497aaac15836b16efe7398b
Binary files /dev/null and b/data/test/json-bulk/IBET/program-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/study-1.json.gz b/data/test/json-bulk/IBET/study-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..97d4457c16859fdbcb17614654aeed1ad3f91770
Binary files /dev/null and b/data/test/json-bulk/IBET/study-1.json.gz differ
diff --git a/data/test/json-bulk/IBET/trial-1.json.gz b/data/test/json-bulk/IBET/trial-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ee2a42e91f5e54310fd5054c102d8240e158170e
Binary files /dev/null and b/data/test/json-bulk/IBET/trial-1.json.gz differ
diff --git a/data/test/json-bulk/NIB/datadiscovery-1.json.gz b/data/test/json-bulk/NIB/datadiscovery-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ce16a2225725825889d223cf2ae7a8a24ecb7661
Binary files /dev/null and b/data/test/json-bulk/NIB/datadiscovery-1.json.gz differ
diff --git a/data/test/json-bulk/NIB/germplasm-1.json.gz b/data/test/json-bulk/NIB/germplasm-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..d78ec183b19e741c0a0d07cc38b0004ccf6e18e8
Binary files /dev/null and b/data/test/json-bulk/NIB/germplasm-1.json.gz differ
diff --git a/data/test/json-bulk/NIB/location-1.json.gz b/data/test/json-bulk/NIB/location-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..cf45bfd7284fcfd1c71bca29cd7c1831c3476996
Binary files /dev/null and b/data/test/json-bulk/NIB/location-1.json.gz differ
diff --git a/data/test/json-bulk/NIB/program-1.json.gz b/data/test/json-bulk/NIB/program-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ef2d384df7e031cd17d6f829e8c8fc17aeb76107
Binary files /dev/null and b/data/test/json-bulk/NIB/program-1.json.gz differ
diff --git a/data/test/json-bulk/NIB/study-1.json.gz b/data/test/json-bulk/NIB/study-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..bdd874019332aaca4abf1f4a3b7af098a33f940e
Binary files /dev/null and b/data/test/json-bulk/NIB/study-1.json.gz differ
diff --git a/data/test/json-bulk/NIB/trial-1.json.gz b/data/test/json-bulk/NIB/trial-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..d0c8b7f50c0a55adb87984f09d08f44df4f87c01
Binary files /dev/null and b/data/test/json-bulk/NIB/trial-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/datadiscovery-1.json.gz b/data/test/json-bulk/URGI/datadiscovery-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..6ac74719f5f4812c9305a67857eaeca758641cfd
Binary files /dev/null and b/data/test/json-bulk/URGI/datadiscovery-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/germplasm-1.json.gz b/data/test/json-bulk/URGI/germplasm-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..4182f9911e850dbf705867510a784b8c8b2ecfa1
Binary files /dev/null and b/data/test/json-bulk/URGI/germplasm-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/germplasmAttribute-1.json.gz b/data/test/json-bulk/URGI/germplasmAttribute-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2fbdf922e61a6f255f6052c9897190d201b5046f
Binary files /dev/null and b/data/test/json-bulk/URGI/germplasmAttribute-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/germplasmMcpd-1.json.gz b/data/test/json-bulk/URGI/germplasmMcpd-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..051c565d78c4d77cc2d6c7d0ea7e0e6345b1758a
Binary files /dev/null and b/data/test/json-bulk/URGI/germplasmMcpd-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/germplasmPedigree-1.json.gz b/data/test/json-bulk/URGI/germplasmPedigree-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..b265e2d8ff5806fa069feef69025c573d2e56435
Binary files /dev/null and b/data/test/json-bulk/URGI/germplasmPedigree-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/germplasmProgeny-1.json.gz b/data/test/json-bulk/URGI/germplasmProgeny-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..0a71aa221bd0ed854dc294b73050a21b9412301b
Binary files /dev/null and b/data/test/json-bulk/URGI/germplasmProgeny-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/location-1.json.gz b/data/test/json-bulk/URGI/location-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..9ee1c92b5c4f86999dfafd34c157cf24d092127b
Binary files /dev/null and b/data/test/json-bulk/URGI/location-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/location-2.json.gz b/data/test/json-bulk/URGI/location-2.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..52eb39da219fb55040b8a113615c168c87b35ec7
Binary files /dev/null and b/data/test/json-bulk/URGI/location-2.json.gz differ
diff --git a/data/test/json-bulk/URGI/program-1.json.gz b/data/test/json-bulk/URGI/program-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..0a3c14b414e7cf2292b50d548125051e85e4fd26
Binary files /dev/null and b/data/test/json-bulk/URGI/program-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/study-1.json.gz b/data/test/json-bulk/URGI/study-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..46c09ea4cdb10a37cc5d0a29185cfe53551e3539
Binary files /dev/null and b/data/test/json-bulk/URGI/study-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/trial-1.json.gz b/data/test/json-bulk/URGI/trial-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..62b52333712c59eed3df6ea037a3c7a3ad8752cc
Binary files /dev/null and b/data/test/json-bulk/URGI/trial-1.json.gz differ
diff --git a/data/test/json-bulk/URGI/xref-1.json.gz b/data/test/json-bulk/URGI/xref-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5a9cfc6637a35c665533c8a3e3fe56f01d16dbe9
Binary files /dev/null and b/data/test/json-bulk/URGI/xref-1.json.gz differ
diff --git a/data/test/json-bulk/VIB/contact-1.json.gz b/data/test/json-bulk/VIB/contact-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..54b1e12086ca58bd09c873f3b34a593808b63360
Binary files /dev/null and b/data/test/json-bulk/VIB/contact-1.json.gz differ
diff --git a/data/test/json-bulk/VIB/datadiscovery-1.json.gz b/data/test/json-bulk/VIB/datadiscovery-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..fea364e682a51449ce081047779b696e3ba7ec11
Binary files /dev/null and b/data/test/json-bulk/VIB/datadiscovery-1.json.gz differ
diff --git a/data/test/json-bulk/VIB/germplasm-1.json.gz b/data/test/json-bulk/VIB/germplasm-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..6382ee91c3896c7a2b710966cf3bde1d8962a2f1
Binary files /dev/null and b/data/test/json-bulk/VIB/germplasm-1.json.gz differ
diff --git a/data/test/json-bulk/VIB/location-1.json.gz b/data/test/json-bulk/VIB/location-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..11fd278b8b2f1c519dddb4b63d0e6102dbe0f63f
Binary files /dev/null and b/data/test/json-bulk/VIB/location-1.json.gz differ
diff --git a/data/test/json-bulk/VIB/observationVariable-1.json.gz b/data/test/json-bulk/VIB/observationVariable-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..75a67505defa784a940fc0ad241c6e3dffc69f94
Binary files /dev/null and b/data/test/json-bulk/VIB/observationVariable-1.json.gz differ
diff --git a/data/test/json-bulk/VIB/study-1.json.gz b/data/test/json-bulk/VIB/study-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..0cb0697649d8e110b39b7fb983252be938a15eeb
Binary files /dev/null and b/data/test/json-bulk/VIB/study-1.json.gz differ
diff --git a/data/test/json-bulk/VIB/trial-1.json.gz b/data/test/json-bulk/VIB/trial-1.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..d16a8f23f65017ace2bbb2a5f1056f4664088e17
Binary files /dev/null and b/data/test/json-bulk/VIB/trial-1.json.gz differ
diff --git a/docker-compose.yml b/docker-compose.yml
index fd9fbf1fe581e4a17e00bea4a3548ba0a2e316c4..9b18aa0f78d997fc40456ab8ba960ae0a547d706 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,15 +1,16 @@
 version: '3.3'
 services:
   elasticsearch:
-    image: docker.elastic.co/elasticsearch/elasticsearch:6.6.2
+    image: docker.elastic.co/elasticsearch/elasticsearch:7.13.2
     container_name: elasticsearch-faidare
     environment:
       - discovery.type=single-node
+      - "ES_JAVA_OPTS=-Dlog4j2.formatMsgNoLookups=true"
     ports:
       - 9200:9200
 
   kibana:
-    image: docker.elastic.co/kibana/kibana:6.6.2
+    image: docker.elastic.co/kibana/kibana:7.13.2
     container_name: kibana-faidare
     environment:
       - "ELASTICSEARCH_URL=http://elasticsearch:9200"
diff --git a/frontend/.gitignore b/frontend/.gitignore
deleted file mode 100644
index 0884bcf52f4bc3cafb618beee8fd0845e35fba80..0000000000000000000000000000000000000000
--- a/frontend/.gitignore
+++ /dev/null
@@ -1,43 +0,0 @@
-
-# Created by https://www.gitignore.io/api/angular,sass
-# Edit at https://www.gitignore.io/?templates=angular,sass
-
-### Angular ###
-## Angular ##
-# compiled output
-/dist
-/tmp
-/app/**/*.js
-/app/**/*.js.map
-
-# dependencies
-/node_modules
-/bower_components
-
-# IDEs and editors
-/.idea
-
-# misc
-/.sass-cache
-/connect.lock
-/coverage/*
-/karma-junit-tests-report
-/libpeerconnection.log
-npm-debug.log
-testem.log
-/typings
-
-# e2e
-/e2e/*.js
-/e2e/*.map
-
-#System Files
-.DS_Store
-
-### Sass ###
-.sass-cache/
-*.css.map
-*.sass.map
-*.scss.map
-
-# End of https://www.gitignore.io/api/angular,sass
diff --git a/frontend/README.md b/frontend/README.md
deleted file mode 100644
index 8bfa0289109d3bcf4e9986830c04a17fd7a5f9b0..0000000000000000000000000000000000000000
--- a/frontend/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# FAIDARE Frontend
-
-This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.0.6.
-
-## Development server
-
-Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
-
-## Code scaffolding
-
-Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
-
-[See official doc for more info](https://github.com/angular/angular-cli/wiki/generate).
-
-## Build
-
-Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
-
-## Running unit tests
-
-Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
-
-## Running end-to-end tests
-
-Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
-
-If you get this error:
-```
-[firefox #11] [11:24:52] I/direct - Using FirefoxDriver directly...
-[firefox #11] [11:24:52] E/direct - Error code: 135
-[firefox #11] [11:24:52] E/direct - Error message: Could not find update-config.json. Run 'webdriver-manager update' to download binaries.
-```
-
-Try to update your web drivers using the following command:
-```sh
-./node_modules/protractor/bin/webdriver-manager update
-```
-
-
-## Further help
-
-To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
diff --git a/frontend/angular.json b/frontend/angular.json
deleted file mode 100644
index 7a7ac6aa69654c186f0dfa581b8af2d0f1278def..0000000000000000000000000000000000000000
--- a/frontend/angular.json
+++ /dev/null
@@ -1,169 +0,0 @@
-{
-  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
-  "version": 1,
-  "newProjectRoot": "projects",
-  "projects": {
-    "frontend": {
-      "root": "",
-      "sourceRoot": "src",
-      "projectType": "application",
-      "prefix": "faidare",
-      "schematics": {
-        "@schematics/angular:component": {
-          "styleext": "scss"
-        }
-      },
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:browser",
-          "options": {
-            "outputPath": "dist/frontend",
-            "index": "src/index.html",
-            "main": "src/main.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "src/tsconfig.app.json",
-            "assets": [
-              {
-                "glob": "**/*",
-                "input": "src/assets/faidare",
-                "output": "/assets"
-              },
-              "src/assets"
-            ],
-            "stylePreprocessorOptions": {
-              "includePaths": [
-                "src/assets/faidare/"
-              ]
-            },
-            "styles": [
-              "src/styles.scss",
-              "node_modules/leaflet/dist/leaflet.css",
-              "node_modules/leaflet.markercluster/dist/MarkerCluster.css",
-              "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css"
-            ],
-            "scripts": [],
-            "baseHref": "/faidare-dev/",
-            "es5BrowserSupport": true
-          },
-          "configurations": {
-            "production": {
-              "fileReplacements": [
-                {
-                  "replace": "src/environments/environment.ts",
-                  "with": "src/environments/environment.prod.ts"
-                }
-              ],
-              "optimization": true,
-              "outputHashing": "all",
-              "sourceMap": false,
-              "extractCss": true,
-              "namedChunks": false,
-              "aot": true,
-              "extractLicenses": true,
-              "vendorChunk": true,
-              "buildOptimizer": true,
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "2000kb",
-                  "maximumError": "4000kb"
-                }
-              ],
-              "stylePreprocessorOptions": {
-                "includePaths": [
-                  "src/assets/faidare/"
-                ]
-              },
-            "baseHref": "./"
-            }
-          }
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "options": {
-            "browserTarget": "frontend:build",
-            "proxyConfig": "proxy.conf.js"
-          },
-          "configurations": {
-            "production": {
-              "browserTarget": "frontend:build:production"
-            }
-          }
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "browsers": "ChromeHeadlessNoSandbox",
-            "main": "src/test.ts",
-            "polyfills": "src/polyfills.ts",
-            "tsConfig": "src/tsconfig.spec.json",
-            "karmaConfig": "src/karma.conf.js",
-            "assets": [
-              {
-                "glob": "**/*",
-                "input": "src/assets/faidare",
-                "output": "/assets"
-              },
-              "src/assets"
-            ],
-            "stylePreprocessorOptions": {
-              "includePaths": [
-                "src/assets/faidare/"
-              ]
-            },
-            "styles": [
-              "src/styles.scss"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "test-multi-browsers": {
-              "browsers": "ChromeHeadlessNoSandbox,FirefoxHeadless"
-            }
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": [
-              "src/tsconfig.app.json",
-              "src/tsconfig.spec.json"
-            ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        }
-      }
-    },
-    "frontend-e2e": {
-      "root": "e2e/",
-      "projectType": "application",
-      "prefix": "",
-      "architect": {
-        "e2e": {
-          "builder": "@angular-devkit/build-angular:protractor",
-          "options": {
-            "protractorConfig": "e2e/protractor.conf.js",
-            "devServerTarget": "frontend:serve"
-          },
-          "configurations": {
-            "production": {
-              "devServerTarget": "frontend:serve:production"
-            }
-          }
-        },
-        "lint": {
-          "builder": "@angular-devkit/build-angular:tslint",
-          "options": {
-            "tsConfig": "e2e/tsconfig.e2e.json",
-            "exclude": [
-              "**/node_modules/**"
-            ]
-          }
-        }
-      }
-    }
-  },
-  "defaultProject": "frontend"
-}
diff --git a/frontend/build.gradle.kts b/frontend/build.gradle.kts
deleted file mode 100644
index c86af189a2098b2890746f80a4292d64bad5946e..0000000000000000000000000000000000000000
--- a/frontend/build.gradle.kts
+++ /dev/null
@@ -1,54 +0,0 @@
-import com.moowork.gradle.node.npm.NpmTask
-
-plugins {
-    base
-    id("com.moowork.node") version "1.2.0"
-    id("org.sonarqube")
-}
-
-val isCi = System.getenv("CI") != null
-
-node {
-    version = "10.13.0"
-    npmVersion = "6.4.1"
-    if (isCi) {
-        // we specify a custom installation directory because of permission issues on Docker
-        workDir = file("/tmp/node")
-    }
-    download = true
-}
-
-
-tasks {
-
-    // Lint
-    val lint by creating {
-        dependsOn("npm_run_lint")
-    }
-
-    // Unit tests
-    val test by creating {
-        if (isCi) {
-            dependsOn("npm_run_test-multi-browsers")
-        } else {
-            dependsOn("npm_run_test")
-        }
-    }
-
-    // E2E tests
-    val clientIntegrationTest by creating {
-        dependsOn("npm_run_e2e")
-    }
-
-    val check by getting {
-        dependsOn(test)
-        dependsOn(lint)
-    }
-
-    // Build assemble
-    val assemble by getting {
-        dependsOn("npm_run_build")
-    }
-
-}
-
diff --git a/frontend/e2e/protractor.conf.js b/frontend/e2e/protractor.conf.js
deleted file mode 100644
index 305723ae0be503ef843199e41c3154a57a9b91ec..0000000000000000000000000000000000000000
--- a/frontend/e2e/protractor.conf.js
+++ /dev/null
@@ -1,44 +0,0 @@
-// Protractor configuration file, see link for more information
-// https://github.com/angular/protractor/blob/master/lib/config.ts
-
-const { SpecReporter } = require('jasmine-spec-reporter');
-
-exports.config = {
-    allScriptsTimeout: 11000,
-    specs: [
-        './src/**/*.e2e-spec.ts'
-    ],
-    directConnect: true,
-    baseUrl: 'http://localhost:4200/',
-    framework: 'jasmine',
-    multiCapabilities: [
-        {
-            browserName: 'chrome',
-            chromeOptions: {
-                args: ["--headless", "--disable-gpu"]
-            }
-        },
-        {
-            browserName: 'firefox',
-            'moz:firefoxOptions': {
-                args: ["--headless"]
-            }
-        }
-    ],
-    jasmineNodeOpts: {
-        showColors: true,
-        defaultTimeoutInterval: 30000,
-        print: function () {
-        }
-    },
-    onPrepare() {
-        require('ts-node').register({
-            project: require('path').join(__dirname, './tsconfig.e2e.json')
-        });
-        jasmine.getEnv().addReporter(
-            new SpecReporter({
-                spec: { displayStacktrace: true }
-            })
-        );
-    }
-};
diff --git a/frontend/e2e/src/app.e2e-spec.ts b/frontend/e2e/src/app.e2e-spec.ts
deleted file mode 100644
index 0d794af9ad135a2f3269e8958561173c83befe6d..0000000000000000000000000000000000000000
--- a/frontend/e2e/src/app.e2e-spec.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { AppPage } from './app.po';
-
-describe('workspace-project App', () => {
-    let page: AppPage;
-
-    beforeEach(() => {
-        page = new AppPage();
-    });
-
-    it('should display result page message', () => {
-        page.navigateTo();
-        expect(page.getLabel('crops')).toContain('Crops');
-    });
-
-    it('should display site card message', () => {
-        page.navigateTo('/sites/FOO');
-        expect(page.getTitleText()).toEqual('sites-card works!');
-    });
-
-    it('should display study card message', () => {
-        page.navigateTo('/studies/BAR');
-        expect(page.getTitleText()).toEqual('study-card works!');
-    });
-
-    it('should display germplasm card message', () => {
-        page.navigateTo('/germplasm/BAZ');
-        expect(page.getTitleText()).toEqual('germplasm-card works!');
-    });
-});
diff --git a/frontend/e2e/src/app.po.ts b/frontend/e2e/src/app.po.ts
deleted file mode 100644
index 59024fc9cfc2c8e71b0169f4f9594bf4b59fea4a..0000000000000000000000000000000000000000
--- a/frontend/e2e/src/app.po.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { browser, by, element } from 'protractor';
-
-export class AppPage {
-    navigateTo(path = '/') {
-        return browser.get(path);
-    }
-
-    getTitleText() {
-        return element(by.css('faidare-root p')).getText();
-    }
-
-    getLabel(id) {
-        return element(by.css('faidare-root label[for=' + id + ']')).getText();
-    }
-}
diff --git a/frontend/e2e/tsconfig.e2e.json b/frontend/e2e/tsconfig.e2e.json
deleted file mode 100644
index a6dd6220282460dae17d69fc030b94ab1e81d960..0000000000000000000000000000000000000000
--- a/frontend/e2e/tsconfig.e2e.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "extends": "../tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../out-tsc/app",
-    "module": "commonjs",
-    "target": "es5",
-    "types": [
-      "jasmine",
-      "jasminewd2",
-      "node"
-    ]
-  }
-}
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
deleted file mode 100644
index 7d778d1b7c43852c2ee50aeae96f7b25de78a0b9..0000000000000000000000000000000000000000
--- a/frontend/package-lock.json
+++ /dev/null
@@ -1,11115 +0,0 @@
-{
-  "name": "frontend",
-  "version": "0.0.0",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "@angular-devkit/architect": {
-      "version": "0.13.2",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.13.2.tgz",
-      "integrity": "sha512-wcUdMzcpsxzscEa+wrhV1SE2PsHS6FnHJlRURFOtQmKvQAq3Y8gVw28l008SMt5d0bTrRV4xLL2lgvwJJoc7LA==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/core": "7.3.2",
-        "rxjs": "6.3.3"
-      },
-      "dependencies": {
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@angular-devkit/build-angular": {
-      "version": "0.13.2",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.13.2.tgz",
-      "integrity": "sha512-zRrV/dknx8891XSjXTh5JcTZnX4h+YsCHi6u8GABnIZW9JyiCl9QZpv0mRIyGTEaK2udmfMo2Yp5qZo1sd8jeQ==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/architect": "0.13.2",
-        "@angular-devkit/build-optimizer": "0.13.2",
-        "@angular-devkit/build-webpack": "0.13.2",
-        "@angular-devkit/core": "7.3.2",
-        "@ngtools/webpack": "7.3.2",
-        "ajv": "6.9.1",
-        "autoprefixer": "9.4.6",
-        "circular-dependency-plugin": "5.0.2",
-        "clean-css": "4.2.1",
-        "copy-webpack-plugin": "4.6.0",
-        "file-loader": "3.0.1",
-        "glob": "7.1.3",
-        "istanbul-instrumenter-loader": "3.0.1",
-        "karma-source-map-support": "1.3.0",
-        "less": "3.9.0",
-        "less-loader": "4.1.0",
-        "license-webpack-plugin": "2.1.0",
-        "loader-utils": "1.2.3",
-        "mini-css-extract-plugin": "0.5.0",
-        "minimatch": "3.0.4",
-        "node-sass": "4.11.0",
-        "opn": "5.4.0",
-        "parse5": "4.0.0",
-        "postcss": "7.0.14",
-        "postcss-import": "12.0.1",
-        "postcss-loader": "3.0.0",
-        "raw-loader": "1.0.0",
-        "rxjs": "6.3.3",
-        "sass-loader": "7.1.0",
-        "semver": "5.6.0",
-        "source-map-loader": "0.2.4",
-        "source-map-support": "0.5.10",
-        "speed-measure-webpack-plugin": "1.3.0",
-        "stats-webpack-plugin": "0.7.0",
-        "style-loader": "0.23.1",
-        "stylus": "0.54.5",
-        "stylus-loader": "3.0.2",
-        "terser-webpack-plugin": "1.2.2",
-        "tree-kill": "1.2.1",
-        "webpack": "4.29.0",
-        "webpack-dev-middleware": "3.5.1",
-        "webpack-dev-server": "3.1.14",
-        "webpack-merge": "4.2.1",
-        "webpack-sources": "1.3.0",
-        "webpack-subresource-integrity": "1.1.0-rc.6"
-      },
-      "dependencies": {
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@angular-devkit/build-optimizer": {
-      "version": "0.13.2",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.13.2.tgz",
-      "integrity": "sha512-pM3t+6VD+gdcesgwuThR41DFdsZ9ZVQ97Hhr0JXHLbLyRt4eXxWi2+B5VL0jjAaX0RIiUIe8wgScwE6m/dxemg==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "1.2.3",
-        "source-map": "0.5.6",
-        "typescript": "3.2.4",
-        "webpack-sources": "1.3.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.6",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
-          "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=",
-          "dev": true
-        }
-      }
-    },
-    "@angular-devkit/build-webpack": {
-      "version": "0.13.2",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.13.2.tgz",
-      "integrity": "sha512-Uemur2KhFu7VGU2QQmfRiMwmoSKprZrMZRZXwZdCQPN5srIcMAgGjm1PGbZuCUddhwd2XRP9dKY6zOZpMzm84Q==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/architect": "0.13.2",
-        "@angular-devkit/core": "7.3.2",
-        "rxjs": "6.3.3"
-      },
-      "dependencies": {
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@angular-devkit/core": {
-      "version": "7.3.2",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.2.tgz",
-      "integrity": "sha512-W5KjkHRNVBcZRUNJamAn52IAj9Gl1zUjPA2r75JJK7k199xOA8UZqcIukQOgM1N7rwKCWht08i4FsdcTDghMhQ==",
-      "dev": true,
-      "requires": {
-        "ajv": "6.9.1",
-        "chokidar": "2.0.4",
-        "fast-json-stable-stringify": "2.0.0",
-        "rxjs": "6.3.3",
-        "source-map": "0.7.3"
-      },
-      "dependencies": {
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@angular-devkit/schematics": {
-      "version": "7.3.4",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-7.3.4.tgz",
-      "integrity": "sha512-BLI4MDHmpzw+snu/2Dw1nMmfJ0VAARTbU6DrmzXyl2Se45+iE/tdRy4yNx3IfHhyoCrVZ15R0y9CXeEsLftlIg==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/core": "7.3.4",
-        "rxjs": "6.3.3"
-      },
-      "dependencies": {
-        "@angular-devkit/core": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.4.tgz",
-          "integrity": "sha512-MBfen51iOBKfK4tlg5KwmPxePsF1QoFNUMGLuvUUwPkteonrGcupX1Q7NWTpf+HA+i08mOnZGuepeuQkD12IQw==",
-          "dev": true,
-          "requires": {
-            "ajv": "6.9.1",
-            "chokidar": "2.0.4",
-            "fast-json-stable-stringify": "2.0.0",
-            "rxjs": "6.3.3",
-            "source-map": "0.7.3"
-          }
-        },
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@angular/animations": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-7.2.7.tgz",
-      "integrity": "sha512-eU/wSkBmukZXCCe/epUl02xsKPauF+deMbncxBE+w/NmmWjJ77Q09iZAcgzM92RVXj2LsVYQXsNEBGT3X0hRZw==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/cli": {
-      "version": "7.3.4",
-      "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-7.3.4.tgz",
-      "integrity": "sha512-uGL8xiQf+GvuJvqvMUu/XHcijbq9ocbX487LO2PgJ29etHfI7dC0toJbQ8ob+HnF9e1qwMe+uu45OU4C2p+a1A==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/architect": "0.13.4",
-        "@angular-devkit/core": "7.3.4",
-        "@angular-devkit/schematics": "7.3.4",
-        "@schematics/angular": "7.3.4",
-        "@schematics/update": "0.13.4",
-        "@yarnpkg/lockfile": "1.1.0",
-        "ini": "1.3.5",
-        "inquirer": "6.2.1",
-        "npm-package-arg": "6.1.0",
-        "opn": "5.4.0",
-        "pacote": "9.4.0",
-        "semver": "5.6.0",
-        "symbol-observable": "1.2.0"
-      },
-      "dependencies": {
-        "@angular-devkit/architect": {
-          "version": "0.13.4",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.13.4.tgz",
-          "integrity": "sha512-wJF8oz8MurtpFi0ik42bkI2F5gEnuOe79KHPO1i3SYfdhEp5NY8igVKZ6chB/eq4Ml50aHxas8Hh9ke12K+Pxw==",
-          "dev": true,
-          "requires": {
-            "@angular-devkit/core": "7.3.4",
-            "rxjs": "6.3.3"
-          }
-        },
-        "@angular-devkit/core": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.4.tgz",
-          "integrity": "sha512-MBfen51iOBKfK4tlg5KwmPxePsF1QoFNUMGLuvUUwPkteonrGcupX1Q7NWTpf+HA+i08mOnZGuepeuQkD12IQw==",
-          "dev": true,
-          "requires": {
-            "ajv": "6.9.1",
-            "chokidar": "2.0.4",
-            "fast-json-stable-stringify": "2.0.0",
-            "rxjs": "6.3.3",
-            "source-map": "0.7.3"
-          }
-        },
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@angular/common": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/common/-/common-7.2.7.tgz",
-      "integrity": "sha512-U1l2CIcmpTAJMWcyTXI9qt1E8CxwKNW1vr6XWZo4X5ziCIzf7RvClzK7Ci5KZKkoPJrJqBJu661Q75Yt22dJsg==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/compiler": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-7.2.7.tgz",
-      "integrity": "sha512-e61YVxW5x4w+X4yjGaptYoJIja7HwH0+8FFEaH6VuPl/DrK8wP4HDMhLo4NzdgeZKLR2jBIQSqLmoM8W7UXcqw==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/compiler-cli": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-7.2.7.tgz",
-      "integrity": "sha512-UPWROJzBLejgNf+aqgEUXYts8UiFOl2IavDhS/olA9irszv2lNFj9Yqr8OKdy0jK/lKaipZog3VZEx8g5dNeBA==",
-      "dev": true,
-      "requires": {
-        "canonical-path": "1.0.0",
-        "chokidar": "^2.1.1",
-        "convert-source-map": "^1.5.1",
-        "dependency-graph": "^0.7.2",
-        "magic-string": "^0.25.0",
-        "minimist": "^1.2.0",
-        "reflect-metadata": "^0.1.2",
-        "shelljs": "^0.8.1",
-        "source-map": "^0.6.1",
-        "tslib": "^1.9.0",
-        "yargs": "9.0.1"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
-        "camelcase": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
-          "dev": true
-        },
-        "chokidar": {
-          "version": "2.1.8",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
-          "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
-          "dev": true,
-          "requires": {
-            "anymatch": "^2.0.0",
-            "async-each": "^1.0.1",
-            "braces": "^2.3.2",
-            "fsevents": "^1.2.7",
-            "glob-parent": "^3.1.0",
-            "inherits": "^2.0.3",
-            "is-binary-path": "^1.0.0",
-            "is-glob": "^4.0.0",
-            "normalize-path": "^3.0.0",
-            "path-is-absolute": "^1.0.0",
-            "readdirp": "^2.2.1",
-            "upath": "^1.1.1"
-          }
-        },
-        "cross-spawn": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
-          "dev": true,
-          "requires": {
-            "lru-cache": "^4.0.1",
-            "shebang-command": "^1.2.0",
-            "which": "^1.2.9"
-          }
-        },
-        "execa": {
-          "version": "0.7.0",
-          "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
-          "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
-          "dev": true,
-          "requires": {
-            "cross-spawn": "^5.0.1",
-            "get-stream": "^3.0.0",
-            "is-stream": "^1.1.0",
-            "npm-run-path": "^2.0.0",
-            "p-finally": "^1.0.0",
-            "signal-exit": "^3.0.0",
-            "strip-eof": "^1.0.0"
-          }
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "load-json-file": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
-          "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "parse-json": "^2.2.0",
-            "pify": "^2.0.0",
-            "strip-bom": "^3.0.0"
-          }
-        },
-        "mem": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
-          "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
-          "dev": true,
-          "requires": {
-            "mimic-fn": "^1.0.0"
-          }
-        },
-        "mimic-fn": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
-          "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
-          "dev": true
-        },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-          "dev": true
-        },
-        "os-locale": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
-          "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
-          "dev": true,
-          "requires": {
-            "execa": "^0.7.0",
-            "lcid": "^1.0.0",
-            "mem": "^1.1.0"
-          }
-        },
-        "path-type": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
-          "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
-          "dev": true,
-          "requires": {
-            "pify": "^2.0.0"
-          }
-        },
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        },
-        "read-pkg": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
-          "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
-          "dev": true,
-          "requires": {
-            "load-json-file": "^2.0.0",
-            "normalize-package-data": "^2.3.2",
-            "path-type": "^2.0.0"
-          }
-        },
-        "read-pkg-up": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
-          "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
-          "dev": true,
-          "requires": {
-            "find-up": "^2.0.0",
-            "read-pkg": "^2.0.0"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-          "dev": true,
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^3.0.0"
-          }
-        },
-        "strip-bom": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-          "dev": true
-        },
-        "which-module": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-          "dev": true
-        },
-        "y18n": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-          "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
-          "dev": true
-        },
-        "yargs": {
-          "version": "9.0.1",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz",
-          "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^4.1.0",
-            "cliui": "^3.2.0",
-            "decamelize": "^1.1.1",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^2.0.0",
-            "read-pkg-up": "^2.0.0",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^2.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^3.2.1",
-            "yargs-parser": "^7.0.0"
-          }
-        },
-        "yargs-parser": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
-          "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^4.1.0"
-          }
-        }
-      }
-    },
-    "@angular/core": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/core/-/core-7.2.7.tgz",
-      "integrity": "sha512-E7qjMQdS77SbRROKu13VsfL+MJN52eTlrU0SzEAFGUOgdvbmDYJOaEwjqrouKpYZ0pul8KOoalvlPB7oVflC7A==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/forms": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-7.2.7.tgz",
-      "integrity": "sha512-2gBs+BG2cMPsHq9JVEzmu2Ev539zjfHmr6cna2W38KLXeGbNf42rbbMUXpYD8cndY0QTYcnwfMpRNIl9zKRZnw==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/http": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/http/-/http-7.2.7.tgz",
-      "integrity": "sha512-HTHYF3qR4S55A+9pyThSOy7++7Makp+klbZTNmpwwJj8yL3qgy9PyDXtf+xhZcUEd8xfXmnz8s4hZr0O9GUy1A==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/language-service": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-7.2.7.tgz",
-      "integrity": "sha512-d3iCBpOfgLNSGMrtqZvN6NHZIEnKD2MV8Hz4WsRLU4WY0RbshZj5dqx2nO3YRT2tACpAvhWBQoYvtLpTCPzsMA==",
-      "dev": true
-    },
-    "@angular/platform-browser": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-7.2.7.tgz",
-      "integrity": "sha512-9C3ffZs0ZUw+dYg1oJKiONf64UKTdAzIOaTQXTrVrCa3oN7Jb2tUfmpenmB+ATRxwhL2n7Yi725YWwxY2FwqvQ==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/platform-browser-dynamic": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.7.tgz",
-      "integrity": "sha512-3nlcwCZOzlKw/4CMJ4zy1JEVy8Ky4KyLRRePLledOMdsGbuDIoq/kyAnBzg295Xe9ovBxv8cmuSkShci+s/x8g==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@angular/router": {
-      "version": "7.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/router/-/router-7.2.7.tgz",
-      "integrity": "sha512-59+M8+IH7V2NPPqWw2mwdg+kh/jfwQcXE0tB8iZ5V2ldACPucY/Td6qiT5H6t7EkELtvkKJwS6vKFV22qdRp3w==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@babel/code-frame": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
-      "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
-      "dev": true,
-      "requires": {
-        "@babel/highlight": "^7.10.4"
-      }
-    },
-    "@babel/generator": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
-      "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.5",
-        "jsesc": "^2.5.1",
-        "source-map": "^0.5.0"
-      },
-      "dependencies": {
-        "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/helper-function-name": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
-      "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-get-function-arity": "^7.10.4",
-        "@babel/template": "^7.10.4",
-        "@babel/types": "^7.10.4"
-      }
-    },
-    "@babel/helper-get-function-arity": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
-      "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.10.4"
-      }
-    },
-    "@babel/helper-split-export-declaration": {
-      "version": "7.11.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
-      "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.11.0"
-      }
-    },
-    "@babel/helper-validator-identifier": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
-      "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
-      "dev": true
-    },
-    "@babel/highlight": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
-      "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.10.4",
-        "chalk": "^2.0.0",
-        "js-tokens": "^4.0.0"
-      },
-      "dependencies": {
-        "js-tokens": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-          "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-          "dev": true
-        }
-      }
-    },
-    "@babel/parser": {
-      "version": "7.12.7",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
-      "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
-      "dev": true
-    },
-    "@babel/template": {
-      "version": "7.12.7",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz",
-      "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.10.4",
-        "@babel/parser": "^7.12.7",
-        "@babel/types": "^7.12.7"
-      }
-    },
-    "@babel/traverse": {
-      "version": "7.12.7",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.7.tgz",
-      "integrity": "sha512-nMWaqsQEeSvMNypswUDzjqQ+0rR6pqCtoQpsqGJC4/Khm9cISwPTSpai57F6/jDaOoEGz8yE/WxcO3PV6tKSmQ==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.10.4",
-        "@babel/generator": "^7.12.5",
-        "@babel/helper-function-name": "^7.10.4",
-        "@babel/helper-split-export-declaration": "^7.11.0",
-        "@babel/parser": "^7.12.7",
-        "@babel/types": "^7.12.7",
-        "debug": "^4.1.0",
-        "globals": "^11.1.0",
-        "lodash": "^4.17.19"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "lodash": {
-          "version": "4.17.20",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
-          "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
-          "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
-        }
-      }
-    },
-    "@babel/types": {
-      "version": "7.12.7",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
-      "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.10.4",
-        "lodash": "^4.17.19",
-        "to-fast-properties": "^2.0.0"
-      },
-      "dependencies": {
-        "lodash": {
-          "version": "4.17.20",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
-          "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
-          "dev": true
-        }
-      }
-    },
-    "@ng-bootstrap/ng-bootstrap": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-4.2.2.tgz",
-      "integrity": "sha512-v8QmC17bv9he5Ep6zutaI9aQ2w/2NqySP0fejOKe7cacKpGUqsLIakpyd2FD7mfZu7pSCCtHYpRWR+h6yq+Ngg==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "@ngtools/webpack": {
-      "version": "7.3.2",
-      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-7.3.2.tgz",
-      "integrity": "sha512-q98nt7HUTcdEtP+aJjsm5HUMDL+BXwLz80TthtFlu/f7JYdKxMSWZRHEv+q8Rs69pWMpwxj8RuHm8XiKD/8Cpg==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/core": "7.3.2",
-        "enhanced-resolve": "4.1.0",
-        "rxjs": "6.3.3",
-        "tree-kill": "1.2.1",
-        "webpack-sources": "1.3.0"
-      },
-      "dependencies": {
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@schematics/angular": {
-      "version": "7.3.4",
-      "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-7.3.4.tgz",
-      "integrity": "sha512-Bb5DZQ8MeP8yhxPe6nVqyQ7sGVNwUx6nXPlrQV45ZycD3nJlqsuxr2DE75HFpn5oU+vlkq9J/Sys4WLJ4E/OMw==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/core": "7.3.4",
-        "@angular-devkit/schematics": "7.3.4",
-        "typescript": "3.2.4"
-      },
-      "dependencies": {
-        "@angular-devkit/core": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.4.tgz",
-          "integrity": "sha512-MBfen51iOBKfK4tlg5KwmPxePsF1QoFNUMGLuvUUwPkteonrGcupX1Q7NWTpf+HA+i08mOnZGuepeuQkD12IQw==",
-          "dev": true,
-          "requires": {
-            "ajv": "6.9.1",
-            "chokidar": "2.0.4",
-            "fast-json-stable-stringify": "2.0.0",
-            "rxjs": "6.3.3",
-            "source-map": "0.7.3"
-          }
-        },
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@schematics/update": {
-      "version": "0.13.4",
-      "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.13.4.tgz",
-      "integrity": "sha512-YarSCCBSVPVG/MyN5H/FliRwaIDoeercy5Nip+NWZJsDyvtsAekO9s6QwizSvAr3541MmSQFeQICsjyM2dl3Bg==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/core": "7.3.4",
-        "@angular-devkit/schematics": "7.3.4",
-        "@yarnpkg/lockfile": "1.1.0",
-        "ini": "1.3.5",
-        "pacote": "9.4.0",
-        "rxjs": "6.3.3",
-        "semver": "5.6.0",
-        "semver-intersect": "1.4.0"
-      },
-      "dependencies": {
-        "@angular-devkit/core": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.4.tgz",
-          "integrity": "sha512-MBfen51iOBKfK4tlg5KwmPxePsF1QoFNUMGLuvUUwPkteonrGcupX1Q7NWTpf+HA+i08mOnZGuepeuQkD12IQw==",
-          "dev": true,
-          "requires": {
-            "ajv": "6.9.1",
-            "chokidar": "2.0.4",
-            "fast-json-stable-stringify": "2.0.0",
-            "rxjs": "6.3.3",
-            "source-map": "0.7.3"
-          }
-        },
-        "rxjs": {
-          "version": "6.3.3",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
-          "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
-      }
-    },
-    "@types/geojson": {
-      "version": "7946.0.6",
-      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.6.tgz",
-      "integrity": "sha512-f6qai3iR62QuMPPdgyH+LyiXTL2n9Rf62UniJjV7KHrbiwzLTZUKsdq0mFSTxAHbO7JvwxwC4tH0m1UnweuLrA=="
-    },
-    "@types/jasmine": {
-      "version": "2.8.12",
-      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.12.tgz",
-      "integrity": "sha512-eE+xeiGBPgQsNcyg61JBqQS6NtxC+s2yfOikMCnc0Z4NqKujzmSahmtjLCKVQU/AyrTEQ76TOwQBnr8wGP2bmA==",
-      "dev": true
-    },
-    "@types/jasminewd2": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.6.tgz",
-      "integrity": "sha512-2ZOKrxb8bKRmP/po5ObYnRDgFE4i+lQiEB27bAMmtMWLgJSqlIDqlLx6S0IRorpOmOPRQ6O80NujTmQAtBkeNw==",
-      "dev": true,
-      "requires": {
-        "@types/jasmine": "*"
-      }
-    },
-    "@types/leaflet": {
-      "version": "1.2.14",
-      "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.2.14.tgz",
-      "integrity": "sha512-acP2w5DygY0V7bwmjFmaen5I2iBl8RkWx9kon1IJA7k9mNFgBb6702WApjZSrM4AG1ucJVxFcTlS6nr4HvahEw==",
-      "requires": {
-        "@types/geojson": "*"
-      }
-    },
-    "@types/leaflet.markercluster": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@types/leaflet.markercluster/-/leaflet.markercluster-1.0.3.tgz",
-      "integrity": "sha512-rz4xQcsD3Ha9TcX4nMba9wpNe7HPQ03Hvo8Osi3SLpfaDCydHMoTquOG1IsjQ2aFm/LIHz4Uo4hYoeLv7q082w==",
-      "requires": {
-        "@types/leaflet": "*"
-      }
-    },
-    "@types/marked": {
-      "version": "0.6.5",
-      "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.6.5.tgz",
-      "integrity": "sha512-6kBKf64aVfx93UJrcyEZ+OBM5nGv4RLsI6sR1Ar34bpgvGVRoyTgpxn4ZmtxOM5aDTAaaznYuYUH8bUX3Nk3YA=="
-    },
-    "@types/node": {
-      "version": "8.9.5",
-      "resolved": "http://registry.npmjs.org/@types/node/-/node-8.9.5.tgz",
-      "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ==",
-      "dev": true
-    },
-    "@types/q": {
-      "version": "0.0.32",
-      "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
-      "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=",
-      "dev": true
-    },
-    "@types/selenium-webdriver": {
-      "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": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
-      "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
-      "dev": true
-    },
-    "@types/webpack-sources": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.8.tgz",
-      "integrity": "sha512-JHB2/xZlXOjzjBB6fMOpH1eQAfsrpqVVIbneE0Rok16WXwFaznaI5vfg75U5WgGJm7V9W1c4xeRQDjX/zwvghA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*",
-        "@types/source-list-map": "*",
-        "source-map": "^0.6.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "@webassemblyjs/ast": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz",
-      "integrity": "sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/helper-module-context": "1.7.11",
-        "@webassemblyjs/helper-wasm-bytecode": "1.7.11",
-        "@webassemblyjs/wast-parser": "1.7.11"
-      }
-    },
-    "@webassemblyjs/floating-point-hex-parser": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz",
-      "integrity": "sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==",
-      "dev": true
-    },
-    "@webassemblyjs/helper-api-error": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz",
-      "integrity": "sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==",
-      "dev": true
-    },
-    "@webassemblyjs/helper-buffer": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz",
-      "integrity": "sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==",
-      "dev": true
-    },
-    "@webassemblyjs/helper-code-frame": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz",
-      "integrity": "sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/wast-printer": "1.7.11"
-      }
-    },
-    "@webassemblyjs/helper-fsm": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz",
-      "integrity": "sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==",
-      "dev": true
-    },
-    "@webassemblyjs/helper-module-context": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz",
-      "integrity": "sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==",
-      "dev": true
-    },
-    "@webassemblyjs/helper-wasm-bytecode": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz",
-      "integrity": "sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==",
-      "dev": true
-    },
-    "@webassemblyjs/helper-wasm-section": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz",
-      "integrity": "sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/helper-buffer": "1.7.11",
-        "@webassemblyjs/helper-wasm-bytecode": "1.7.11",
-        "@webassemblyjs/wasm-gen": "1.7.11"
-      }
-    },
-    "@webassemblyjs/ieee754": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz",
-      "integrity": "sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==",
-      "dev": true,
-      "requires": {
-        "@xtuc/ieee754": "^1.2.0"
-      }
-    },
-    "@webassemblyjs/leb128": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.11.tgz",
-      "integrity": "sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==",
-      "dev": true,
-      "requires": {
-        "@xtuc/long": "4.2.1"
-      }
-    },
-    "@webassemblyjs/utf8": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.11.tgz",
-      "integrity": "sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==",
-      "dev": true
-    },
-    "@webassemblyjs/wasm-edit": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz",
-      "integrity": "sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/helper-buffer": "1.7.11",
-        "@webassemblyjs/helper-wasm-bytecode": "1.7.11",
-        "@webassemblyjs/helper-wasm-section": "1.7.11",
-        "@webassemblyjs/wasm-gen": "1.7.11",
-        "@webassemblyjs/wasm-opt": "1.7.11",
-        "@webassemblyjs/wasm-parser": "1.7.11",
-        "@webassemblyjs/wast-printer": "1.7.11"
-      }
-    },
-    "@webassemblyjs/wasm-gen": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz",
-      "integrity": "sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/helper-wasm-bytecode": "1.7.11",
-        "@webassemblyjs/ieee754": "1.7.11",
-        "@webassemblyjs/leb128": "1.7.11",
-        "@webassemblyjs/utf8": "1.7.11"
-      }
-    },
-    "@webassemblyjs/wasm-opt": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz",
-      "integrity": "sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/helper-buffer": "1.7.11",
-        "@webassemblyjs/wasm-gen": "1.7.11",
-        "@webassemblyjs/wasm-parser": "1.7.11"
-      }
-    },
-    "@webassemblyjs/wasm-parser": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz",
-      "integrity": "sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/helper-api-error": "1.7.11",
-        "@webassemblyjs/helper-wasm-bytecode": "1.7.11",
-        "@webassemblyjs/ieee754": "1.7.11",
-        "@webassemblyjs/leb128": "1.7.11",
-        "@webassemblyjs/utf8": "1.7.11"
-      }
-    },
-    "@webassemblyjs/wast-parser": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz",
-      "integrity": "sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/floating-point-hex-parser": "1.7.11",
-        "@webassemblyjs/helper-api-error": "1.7.11",
-        "@webassemblyjs/helper-code-frame": "1.7.11",
-        "@webassemblyjs/helper-fsm": "1.7.11",
-        "@xtuc/long": "4.2.1"
-      }
-    },
-    "@webassemblyjs/wast-printer": {
-      "version": "1.7.11",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz",
-      "integrity": "sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/wast-parser": "1.7.11",
-        "@xtuc/long": "4.2.1"
-      }
-    },
-    "@xtuc/ieee754": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
-      "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
-      "dev": true
-    },
-    "@xtuc/long": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz",
-      "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==",
-      "dev": true
-    },
-    "@yarnpkg/lockfile": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
-      "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
-      "dev": true
-    },
-    "JSONStream": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
-      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
-      "dev": true,
-      "requires": {
-        "jsonparse": "^1.2.0",
-        "through": ">=2.2.7 <3"
-      }
-    },
-    "abbrev": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
-      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
-      "dev": true,
-      "optional": true
-    },
-    "accepts": {
-      "version": "1.3.7",
-      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
-      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
-      "dev": true,
-      "requires": {
-        "mime-types": "~2.1.24",
-        "negotiator": "0.6.2"
-      }
-    },
-    "acorn": {
-      "version": "6.4.2",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
-      "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
-      "dev": true
-    },
-    "acorn-dynamic-import": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
-      "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==",
-      "dev": true
-    },
-    "adm-zip": {
-      "version": "0.4.16",
-      "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
-      "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==",
-      "dev": true
-    },
-    "after": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
-      "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
-      "dev": true
-    },
-    "agent-base": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
-      "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
-      "dev": true,
-      "requires": {
-        "es6-promisify": "^5.0.0"
-      }
-    },
-    "agentkeepalive": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
-      "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==",
-      "dev": true,
-      "requires": {
-        "humanize-ms": "^1.2.1"
-      }
-    },
-    "ajv": {
-      "version": "6.9.1",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz",
-      "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==",
-      "dev": true,
-      "requires": {
-        "fast-deep-equal": "^2.0.1",
-        "fast-json-stable-stringify": "^2.0.0",
-        "json-schema-traverse": "^0.4.1",
-        "uri-js": "^4.2.2"
-      }
-    },
-    "ajv-errors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
-      "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
-      "dev": true
-    },
-    "ajv-keywords": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
-      "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
-      "dev": true
-    },
-    "amdefine": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
-      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
-      "dev": true
-    },
-    "angular-coordinates": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/angular-coordinates/-/angular-coordinates-1.0.0.tgz",
-      "integrity": "sha1-IcuYpv+PTV6LWLjOjvzBP7elnug="
-    },
-    "angular-mocks": {
-      "version": "1.7.8",
-      "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.8.tgz",
-      "integrity": "sha512-LB13ESBT0eJrhQhfPXyLR9qm4LI9g44hyBFwUqZKEHEA4DpfxVTu0ONipiNoN0zWtmEAezA8u2gjcoaO2TStig=="
-    },
-    "ansi-colors": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
-      "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
-      "dev": true
-    },
-    "ansi-escapes": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
-      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
-      "dev": true
-    },
-    "ansi-html": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
-      "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
-      "dev": true
-    },
-    "ansi-regex": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-      "dev": true
-    },
-    "ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dev": true,
-      "requires": {
-        "color-convert": "^1.9.0"
-      }
-    },
-    "anymatch": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
-      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
-      "dev": true,
-      "requires": {
-        "micromatch": "^3.1.4",
-        "normalize-path": "^2.1.1"
-      }
-    },
-    "app-root-path": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz",
-      "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==",
-      "dev": true
-    },
-    "append-transform": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
-      "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
-      "dev": true,
-      "requires": {
-        "default-require-extensions": "^2.0.0"
-      }
-    },
-    "aproba": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
-      "dev": true
-    },
-    "are-we-there-yet": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
-      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
-      "dev": true,
-      "requires": {
-        "delegates": "^1.0.0",
-        "readable-stream": "^2.0.6"
-      }
-    },
-    "argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "dev": true,
-      "requires": {
-        "sprintf-js": "~1.0.2"
-      }
-    },
-    "aria-query": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
-      "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
-      "dev": true,
-      "requires": {
-        "ast-types-flow": "0.0.7",
-        "commander": "^2.11.0"
-      }
-    },
-    "arr-diff": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
-      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
-      "dev": true
-    },
-    "arr-flatten": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
-      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
-      "dev": true
-    },
-    "arr-union": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
-      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
-      "dev": true
-    },
-    "array-find-index": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
-      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
-      "dev": true,
-      "optional": true
-    },
-    "array-flatten": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
-      "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
-      "dev": true
-    },
-    "array-union": {
-      "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"
-      }
-    },
-    "array-uniq": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
-      "dev": true
-    },
-    "array-unique": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
-      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
-      "dev": true
-    },
-    "arraybuffer.slice": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
-      "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
-      "dev": true
-    },
-    "arrify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
-      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
-      "dev": true
-    },
-    "asap": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-      "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
-      "dev": true,
-      "optional": true
-    },
-    "asn1": {
-      "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"
-      }
-    },
-    "asn1.js": {
-      "version": "5.4.1",
-      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
-      "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.0.0",
-        "inherits": "^2.0.1",
-        "minimalistic-assert": "^1.0.0",
-        "safer-buffer": "^2.1.0"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "assert": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
-      "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
-      "dev": true,
-      "requires": {
-        "object-assign": "^4.1.1",
-        "util": "0.10.3"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
-          "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
-          "dev": true
-        },
-        "util": {
-          "version": "0.10.3",
-          "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
-          "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
-          "dev": true,
-          "requires": {
-            "inherits": "2.0.1"
-          }
-        }
-      }
-    },
-    "assert-plus": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
-      "dev": true
-    },
-    "assign-symbols": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
-      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
-      "dev": true
-    },
-    "ast-types-flow": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
-      "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
-      "dev": true
-    },
-    "async": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
-      "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.11"
-      }
-    },
-    "async-each": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
-      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
-      "dev": true
-    },
-    "async-foreach": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
-      "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
-      "dev": true,
-      "optional": true
-    },
-    "async-limiter": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
-      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
-      "dev": true
-    },
-    "asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
-      "dev": true
-    },
-    "atob": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
-      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
-      "dev": true
-    },
-    "autoprefixer": {
-      "version": "9.4.6",
-      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.6.tgz",
-      "integrity": "sha512-Yp51mevbOEdxDUy5WjiKtpQaecqYq9OqZSL04rSoCiry7Tc5I9FEyo3bfxiTJc1DfHeKwSFCUYbBAiOQ2VGfiw==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.4.1",
-        "caniuse-lite": "^1.0.30000929",
-        "normalize-range": "^0.1.2",
-        "num2fraction": "^1.2.2",
-        "postcss": "^7.0.13",
-        "postcss-value-parser": "^3.3.1"
-      }
-    },
-    "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=",
-      "dev": true
-    },
-    "aws4": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
-      "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
-      "dev": true
-    },
-    "axobject-query": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
-      "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
-      "dev": true,
-      "requires": {
-        "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"
-          }
-        },
-        "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-generator": {
-      "version": "6.26.1",
-      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
-      "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
-      "dev": true,
-      "requires": {
-        "babel-messages": "^6.23.0",
-        "babel-runtime": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "detect-indent": "^4.0.0",
-        "jsesc": "^1.3.0",
-        "lodash": "^4.17.4",
-        "source-map": "^0.5.7",
-        "trim-right": "^1.0.1"
-      },
-      "dependencies": {
-        "jsesc": {
-          "version": "1.3.0",
-          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
-          "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
-          "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-messages": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
-      "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-runtime": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
-      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
-      "dev": true,
-      "requires": {
-        "core-js": "^2.4.0",
-        "regenerator-runtime": "^0.11.0"
-      }
-    },
-    "babel-template": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
-      "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.26.0",
-        "babel-traverse": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "babylon": "^6.18.0",
-        "lodash": "^4.17.4"
-      }
-    },
-    "babel-traverse": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
-      "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
-      "dev": true,
-      "requires": {
-        "babel-code-frame": "^6.26.0",
-        "babel-messages": "^6.23.0",
-        "babel-runtime": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "babylon": "^6.18.0",
-        "debug": "^2.6.8",
-        "globals": "^9.18.0",
-        "invariant": "^2.2.2",
-        "lodash": "^4.17.4"
-      },
-      "dependencies": {
-        "globals": {
-          "version": "9.18.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
-          "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
-          "dev": true
-        }
-      }
-    },
-    "babel-types": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
-      "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.26.0",
-        "esutils": "^2.0.2",
-        "lodash": "^4.17.4",
-        "to-fast-properties": "^1.0.3"
-      },
-      "dependencies": {
-        "to-fast-properties": {
-          "version": "1.0.3",
-          "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
-          "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
-          "dev": true
-        }
-      }
-    },
-    "babylon": {
-      "version": "6.18.0",
-      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
-      "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
-      "dev": true
-    },
-    "backo2": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
-      "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
-      "dev": true
-    },
-    "balanced-match": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-      "dev": true
-    },
-    "base": {
-      "version": "0.11.2",
-      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
-      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
-      "dev": true,
-      "requires": {
-        "cache-base": "^1.0.1",
-        "class-utils": "^0.3.5",
-        "component-emitter": "^1.2.1",
-        "define-property": "^1.0.0",
-        "isobject": "^3.0.1",
-        "mixin-deep": "^1.2.0",
-        "pascalcase": "^0.1.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
-    "base64-arraybuffer": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
-      "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
-      "dev": true
-    },
-    "base64-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-      "dev": true
-    },
-    "base64id": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
-      "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=",
-      "dev": true
-    },
-    "batch": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
-      "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
-      "dev": true
-    },
-    "bcrypt-pbkdf": {
-      "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"
-      }
-    },
-    "better-assert": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
-      "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
-      "dev": true,
-      "requires": {
-        "callsite": "1.0.0"
-      }
-    },
-    "big.js": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-      "dev": true
-    },
-    "binary-extensions": {
-      "version": "1.13.1",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
-      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
-      "dev": true
-    },
-    "bindings": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
-      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "file-uri-to-path": "1.0.0"
-      }
-    },
-    "blob": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
-      "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
-      "dev": true
-    },
-    "block-stream": {
-      "version": "0.0.9",
-      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
-      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "inherits": "~2.0.0"
-      }
-    },
-    "blocking-proxy": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz",
-      "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==",
-      "dev": true,
-      "requires": {
-        "minimist": "^1.2.0"
-      }
-    },
-    "bluebird": {
-      "version": "3.7.2",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
-      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
-      "dev": true
-    },
-    "bn.js": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
-      "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
-      "dev": true
-    },
-    "body-parser": {
-      "version": "1.19.0",
-      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
-      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
-      "dev": true,
-      "requires": {
-        "bytes": "3.1.0",
-        "content-type": "~1.0.4",
-        "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "http-errors": "1.7.2",
-        "iconv-lite": "0.4.24",
-        "on-finished": "~2.3.0",
-        "qs": "6.7.0",
-        "raw-body": "2.4.0",
-        "type-is": "~1.6.17"
-      },
-      "dependencies": {
-        "bytes": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
-          "dev": true
-        },
-        "qs": {
-          "version": "6.7.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
-          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
-          "dev": true
-        }
-      }
-    },
-    "bonjour": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
-      "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
-      "dev": true,
-      "requires": {
-        "array-flatten": "^2.1.0",
-        "deep-equal": "^1.0.1",
-        "dns-equal": "^1.0.0",
-        "dns-txt": "^2.0.2",
-        "multicast-dns": "^6.0.1",
-        "multicast-dns-service-types": "^1.1.0"
-      }
-    },
-    "bootstrap": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
-      "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag=="
-    },
-    "brace-expansion": {
-      "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"
-      }
-    },
-    "braces": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
-      "dev": true,
-      "requires": {
-        "arr-flatten": "^1.1.0",
-        "array-unique": "^0.3.2",
-        "extend-shallow": "^2.0.1",
-        "fill-range": "^4.0.0",
-        "isobject": "^3.0.1",
-        "repeat-element": "^1.1.2",
-        "snapdragon": "^0.8.1",
-        "snapdragon-node": "^2.0.1",
-        "split-string": "^3.0.2",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "brorand": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
-      "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
-      "dev": true
-    },
-    "browserify-aes": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
-      "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
-      "dev": true,
-      "requires": {
-        "buffer-xor": "^1.0.3",
-        "cipher-base": "^1.0.0",
-        "create-hash": "^1.1.0",
-        "evp_bytestokey": "^1.0.3",
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "browserify-cipher": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
-      "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
-      "dev": true,
-      "requires": {
-        "browserify-aes": "^1.0.4",
-        "browserify-des": "^1.0.0",
-        "evp_bytestokey": "^1.0.0"
-      }
-    },
-    "browserify-des": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
-      "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
-      "dev": true,
-      "requires": {
-        "cipher-base": "^1.0.1",
-        "des.js": "^1.0.0",
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.1.2"
-      }
-    },
-    "browserify-rsa": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
-      "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^5.0.0",
-        "randombytes": "^2.0.1"
-      }
-    },
-    "browserify-sign": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
-      "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^5.1.1",
-        "browserify-rsa": "^4.0.1",
-        "create-hash": "^1.2.0",
-        "create-hmac": "^1.1.7",
-        "elliptic": "^6.5.3",
-        "inherits": "^2.0.4",
-        "parse-asn1": "^5.1.5",
-        "readable-stream": "^3.6.0",
-        "safe-buffer": "^5.2.0"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-          "dev": true
-        },
-        "readable-stream": {
-          "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",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.2.1",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-          "dev": true
-        }
-      }
-    },
-    "browserify-zlib": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
-      "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
-      "dev": true,
-      "requires": {
-        "pako": "~1.0.5"
-      }
-    },
-    "browserslist": {
-      "version": "4.14.7",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz",
-      "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==",
-      "dev": true,
-      "requires": {
-        "caniuse-lite": "^1.0.30001157",
-        "colorette": "^1.2.1",
-        "electron-to-chromium": "^1.3.591",
-        "escalade": "^3.1.1",
-        "node-releases": "^1.1.66"
-      }
-    },
-    "browserstack": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.0.tgz",
-      "integrity": "sha512-HJDJ0TSlmkwnt9RZ+v5gFpa1XZTBYTj0ywvLwJ3241J7vMw2jAsGNVhKHtmCOyg+VxeLZyaibO9UL71AsUeDIw==",
-      "dev": true,
-      "requires": {
-        "https-proxy-agent": "^2.2.1"
-      }
-    },
-    "buffer": {
-      "version": "4.9.2",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
-      "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
-      "dev": true,
-      "requires": {
-        "base64-js": "^1.0.2",
-        "ieee754": "^1.1.4",
-        "isarray": "^1.0.0"
-      }
-    },
-    "buffer-alloc": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
-      "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
-      "dev": true,
-      "requires": {
-        "buffer-alloc-unsafe": "^1.1.0",
-        "buffer-fill": "^1.0.0"
-      }
-    },
-    "buffer-alloc-unsafe": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
-      "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
-      "dev": true
-    },
-    "buffer-fill": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
-      "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
-      "dev": true
-    },
-    "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==",
-      "dev": true
-    },
-    "buffer-indexof": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
-      "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
-      "dev": true
-    },
-    "buffer-xor": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
-      "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
-      "dev": true
-    },
-    "builtin-modules": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
-      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
-      "dev": true
-    },
-    "builtin-status-codes": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
-      "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
-      "dev": true
-    },
-    "builtins": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
-      "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=",
-      "dev": true
-    },
-    "bytes": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
-      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
-      "dev": true
-    },
-    "cacache": {
-      "version": "10.0.4",
-      "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz",
-      "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==",
-      "dev": true,
-      "requires": {
-        "bluebird": "^3.5.1",
-        "chownr": "^1.0.1",
-        "glob": "^7.1.2",
-        "graceful-fs": "^4.1.11",
-        "lru-cache": "^4.1.1",
-        "mississippi": "^2.0.0",
-        "mkdirp": "^0.5.1",
-        "move-concurrently": "^1.0.1",
-        "promise-inflight": "^1.0.1",
-        "rimraf": "^2.6.2",
-        "ssri": "^5.2.4",
-        "unique-filename": "^1.1.0",
-        "y18n": "^4.0.0"
-      }
-    },
-    "cache-base": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
-      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
-      "dev": true,
-      "requires": {
-        "collection-visit": "^1.0.0",
-        "component-emitter": "^1.2.1",
-        "get-value": "^2.0.6",
-        "has-value": "^1.0.0",
-        "isobject": "^3.0.1",
-        "set-value": "^2.0.0",
-        "to-object-path": "^0.3.0",
-        "union-value": "^1.0.0",
-        "unset-value": "^1.0.0"
-      }
-    },
-    "call-bind": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
-      "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.0"
-      }
-    },
-    "caller-callsite": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
-      "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
-      "dev": true,
-      "requires": {
-        "callsites": "^2.0.0"
-      }
-    },
-    "caller-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
-      "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
-      "dev": true,
-      "requires": {
-        "caller-callsite": "^2.0.0"
-      }
-    },
-    "callsite": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
-      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
-      "dev": true
-    },
-    "callsites": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
-      "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
-      "dev": true
-    },
-    "camelcase": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
-      "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
-      "dev": true,
-      "optional": true
-    },
-    "camelcase-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
-      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "camelcase": "^2.0.0",
-        "map-obj": "^1.0.0"
-      }
-    },
-    "caniuse-lite": {
-      "version": "1.0.30001159",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001159.tgz",
-      "integrity": "sha512-w9Ph56jOsS8RL20K9cLND3u/+5WASWdhC/PPrf+V3/HsM3uHOavWOR1Xzakbv4Puo/srmPHudkmCRWM7Aq+/UA==",
-      "dev": true
-    },
-    "canonical-path": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz",
-      "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
-      "dev": true
-    },
-    "caseless": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
-      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
-      "dev": true
-    },
-    "chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
-      },
-      "dependencies": {
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "chardet": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
-      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
-      "dev": true
-    },
-    "chokidar": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
-      "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==",
-      "dev": true,
-      "requires": {
-        "anymatch": "^2.0.0",
-        "async-each": "^1.0.0",
-        "braces": "^2.3.0",
-        "fsevents": "^1.2.2",
-        "glob-parent": "^3.1.0",
-        "inherits": "^2.0.1",
-        "is-binary-path": "^1.0.0",
-        "is-glob": "^4.0.0",
-        "lodash.debounce": "^4.0.8",
-        "normalize-path": "^2.1.1",
-        "path-is-absolute": "^1.0.0",
-        "readdirp": "^2.0.0",
-        "upath": "^1.0.5"
-      }
-    },
-    "chownr": {
-      "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": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
-      "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "cipher-base": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
-      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "circular-dependency-plugin": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz",
-      "integrity": "sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA==",
-      "dev": true
-    },
-    "class-utils": {
-      "version": "0.3.6",
-      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
-      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
-      "dev": true,
-      "requires": {
-        "arr-union": "^3.1.0",
-        "define-property": "^0.2.5",
-        "isobject": "^3.0.0",
-        "static-extend": "^0.1.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        }
-      }
-    },
-    "clean-css": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
-      "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
-      "dev": true,
-      "requires": {
-        "source-map": "~0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "cli-cursor": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
-      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
-      "dev": true,
-      "requires": {
-        "restore-cursor": "^2.0.0"
-      }
-    },
-    "cli-width": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
-      "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
-      "dev": true
-    },
-    "clipboard": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
-      "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
-      "optional": true,
-      "requires": {
-        "good-listener": "^1.2.2",
-        "select": "^1.1.2",
-        "tiny-emitter": "^2.0.0"
-      }
-    },
-    "cliui": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
-      "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
-      "dev": true,
-      "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1",
-        "wrap-ansi": "^2.0.0"
-      }
-    },
-    "clone": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
-      "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
-      "dev": true
-    },
-    "clone-deep": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz",
-      "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==",
-      "dev": true,
-      "requires": {
-        "for-own": "^1.0.0",
-        "is-plain-object": "^2.0.4",
-        "kind-of": "^6.0.0",
-        "shallow-clone": "^1.0.0"
-      }
-    },
-    "co": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
-      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
-      "dev": true
-    },
-    "code-point-at": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
-      "dev": true
-    },
-    "codelyzer": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.2.tgz",
-      "integrity": "sha512-jB4FZ1Sx7kZhvZVdf+N2BaKTdrrNZOL0Bj10RRfrhHrb3zEvXjJvvq298JPMJAiyiCS/v4zs1QlGU0ip7xGqeA==",
-      "dev": true,
-      "requires": {
-        "app-root-path": "^2.2.1",
-        "aria-query": "^3.0.0",
-        "axobject-query": "2.0.2",
-        "css-selector-tokenizer": "^0.7.1",
-        "cssauron": "^1.4.0",
-        "damerau-levenshtein": "^1.0.4",
-        "semver-dsl": "^1.0.1",
-        "source-map": "^0.5.7",
-        "sprintf-js": "^1.1.2"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        },
-        "sprintf-js": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
-          "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
-          "dev": true
-        }
-      }
-    },
-    "collection-visit": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
-      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
-      "dev": true,
-      "requires": {
-        "map-visit": "^1.0.0",
-        "object-visit": "^1.0.0"
-      }
-    },
-    "color-convert": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dev": true,
-      "requires": {
-        "color-name": "1.1.3"
-      }
-    },
-    "color-name": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-      "dev": true
-    },
-    "colorette": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
-      "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
-      "dev": true
-    },
-    "colors": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
-      "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
-      "dev": true
-    },
-    "combined-stream": {
-      "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"
-      }
-    },
-    "commander": {
-      "version": "2.17.1",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
-      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
-      "dev": true
-    },
-    "commondir": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
-      "dev": true
-    },
-    "compare-versions": {
-      "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": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
-      "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
-      "dev": true
-    },
-    "component-emitter": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
-      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
-      "dev": true
-    },
-    "component-inherit": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
-      "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
-      "dev": true
-    },
-    "compressible": {
-      "version": "2.0.18",
-      "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
-      "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
-      "dev": true,
-      "requires": {
-        "mime-db": ">= 1.43.0 < 2"
-      }
-    },
-    "compression": {
-      "version": "1.7.4",
-      "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
-      "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
-      "dev": true,
-      "requires": {
-        "accepts": "~1.3.5",
-        "bytes": "3.0.0",
-        "compressible": "~2.0.16",
-        "debug": "2.6.9",
-        "on-headers": "~1.0.2",
-        "safe-buffer": "5.1.2",
-        "vary": "~1.1.2"
-      }
-    },
-    "concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "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",
-        "readable-stream": "^2.2.2",
-        "typedarray": "^0.0.6"
-      }
-    },
-    "connect": {
-      "version": "3.7.0",
-      "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
-      "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
-      "dev": true,
-      "requires": {
-        "debug": "2.6.9",
-        "finalhandler": "1.1.2",
-        "parseurl": "~1.3.3",
-        "utils-merge": "1.0.1"
-      }
-    },
-    "connect-history-api-fallback": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
-      "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
-      "dev": true
-    },
-    "console-browserify": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
-      "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
-      "dev": true
-    },
-    "console-control-strings": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
-      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
-      "dev": true
-    },
-    "constants-browserify": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
-      "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
-      "dev": true
-    },
-    "content-disposition": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
-      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "5.1.2"
-      }
-    },
-    "content-type": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
-      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
-      "dev": true
-    },
-    "convert-source-map": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
-      "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.1.1"
-      }
-    },
-    "cookie": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
-      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
-      "dev": true
-    },
-    "cookie-signature": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
-      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
-      "dev": true
-    },
-    "copy-concurrently": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
-      "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
-      "dev": true,
-      "requires": {
-        "aproba": "^1.1.1",
-        "fs-write-stream-atomic": "^1.0.8",
-        "iferr": "^0.1.5",
-        "mkdirp": "^0.5.1",
-        "rimraf": "^2.5.4",
-        "run-queue": "^1.0.0"
-      }
-    },
-    "copy-descriptor": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
-      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
-      "dev": true
-    },
-    "copy-webpack-plugin": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz",
-      "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==",
-      "dev": true,
-      "requires": {
-        "cacache": "^10.0.4",
-        "find-cache-dir": "^1.0.0",
-        "globby": "^7.1.1",
-        "is-glob": "^4.0.0",
-        "loader-utils": "^1.1.0",
-        "minimatch": "^3.0.4",
-        "p-limit": "^1.0.0",
-        "serialize-javascript": "^1.4.0"
-      }
-    },
-    "core-js": {
-      "version": "2.5.7",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
-      "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
-    },
-    "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=",
-      "dev": true
-    },
-    "cosmiconfig": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
-      "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
-      "dev": true,
-      "requires": {
-        "import-fresh": "^2.0.0",
-        "is-directory": "^0.3.1",
-        "js-yaml": "^3.13.1",
-        "parse-json": "^4.0.0"
-      },
-      "dependencies": {
-        "parse-json": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
-          "dev": true,
-          "requires": {
-            "error-ex": "^1.3.1",
-            "json-parse-better-errors": "^1.0.1"
-          }
-        }
-      }
-    },
-    "create-ecdh": {
-      "version": "4.0.4",
-      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
-      "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.1.0",
-        "elliptic": "^6.5.3"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "create-hash": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
-      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
-      "dev": true,
-      "requires": {
-        "cipher-base": "^1.0.1",
-        "inherits": "^2.0.1",
-        "md5.js": "^1.3.4",
-        "ripemd160": "^2.0.1",
-        "sha.js": "^2.4.0"
-      }
-    },
-    "create-hmac": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
-      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
-      "dev": true,
-      "requires": {
-        "cipher-base": "^1.0.3",
-        "create-hash": "^1.1.0",
-        "inherits": "^2.0.1",
-        "ripemd160": "^2.0.0",
-        "safe-buffer": "^5.0.1",
-        "sha.js": "^2.4.8"
-      }
-    },
-    "cross-spawn": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
-      "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "lru-cache": "^4.0.1",
-        "which": "^1.2.9"
-      }
-    },
-    "crypto-browserify": {
-      "version": "3.12.0",
-      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
-      "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
-      "dev": true,
-      "requires": {
-        "browserify-cipher": "^1.0.0",
-        "browserify-sign": "^4.0.0",
-        "create-ecdh": "^4.0.0",
-        "create-hash": "^1.1.0",
-        "create-hmac": "^1.1.0",
-        "diffie-hellman": "^5.0.0",
-        "inherits": "^2.0.1",
-        "pbkdf2": "^3.0.3",
-        "public-encrypt": "^4.0.0",
-        "randombytes": "^2.0.0",
-        "randomfill": "^1.0.3"
-      }
-    },
-    "css-parse": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz",
-      "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=",
-      "dev": true
-    },
-    "css-selector-tokenizer": {
-      "version": "0.7.3",
-      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
-      "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
-      "dev": true,
-      "requires": {
-        "cssesc": "^3.0.0",
-        "fastparse": "^1.1.2"
-      }
-    },
-    "cssauron": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
-      "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
-      "dev": true,
-      "requires": {
-        "through": "X.X.X"
-      }
-    },
-    "cssesc": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
-      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
-      "dev": true
-    },
-    "currently-unhandled": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
-      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "array-find-index": "^1.0.1"
-      }
-    },
-    "custom-event": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
-      "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
-      "dev": true
-    },
-    "cyclist": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
-      "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
-      "dev": true
-    },
-    "damerau-levenshtein": {
-      "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"
-      }
-    },
-    "date-format": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
-      "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==",
-      "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"
-      }
-    },
-    "decamelize": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
-      "dev": true
-    },
-    "decode-uri-component": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
-      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
-      "dev": true
-    },
-    "deep-equal": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
-      "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
-      "dev": true,
-      "requires": {
-        "is-arguments": "^1.0.4",
-        "is-date-object": "^1.0.1",
-        "is-regex": "^1.0.4",
-        "object-is": "^1.0.1",
-        "object-keys": "^1.1.1",
-        "regexp.prototype.flags": "^1.2.0"
-      }
-    },
-    "default-gateway": {
-      "version": "2.7.2",
-      "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.2.tgz",
-      "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==",
-      "dev": true,
-      "requires": {
-        "execa": "^0.10.0",
-        "ip-regex": "^2.1.0"
-      }
-    },
-    "default-require-extensions": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
-      "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=",
-      "dev": true,
-      "requires": {
-        "strip-bom": "^3.0.0"
-      },
-      "dependencies": {
-        "strip-bom": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-          "dev": true
-        }
-      }
-    },
-    "define-properties": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
-      "dev": true,
-      "requires": {
-        "object-keys": "^1.0.12"
-      }
-    },
-    "define-property": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
-      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
-      "dev": true,
-      "requires": {
-        "is-descriptor": "^1.0.2",
-        "isobject": "^3.0.1"
-      },
-      "dependencies": {
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
-    "del": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz",
-      "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=",
-      "dev": true,
-      "requires": {
-        "globby": "^6.1.0",
-        "is-path-cwd": "^1.0.0",
-        "is-path-in-cwd": "^1.0.0",
-        "p-map": "^1.1.1",
-        "pify": "^3.0.0",
-        "rimraf": "^2.2.8"
-      },
-      "dependencies": {
-        "globby": {
-          "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",
-            "object-assign": "^4.0.1",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          },
-          "dependencies": {
-            "pify": {
-              "version": "2.3.0",
-              "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-              "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-              "dev": true
-            }
-          }
-        }
-      }
-    },
-    "delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
-      "dev": true
-    },
-    "delegate": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
-      "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
-      "optional": true
-    },
-    "delegates": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
-      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
-      "dev": true
-    },
-    "depd": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
-      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
-      "dev": true
-    },
-    "dependency-graph": {
-      "version": "0.7.2",
-      "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz",
-      "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==",
-      "dev": true
-    },
-    "des.js": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
-      "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "minimalistic-assert": "^1.0.0"
-      }
-    },
-    "destroy": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
-      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
-      "dev": true
-    },
-    "detect-indent": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
-      "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
-      "dev": true,
-      "requires": {
-        "repeating": "^2.0.0"
-      }
-    },
-    "detect-node": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
-      "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
-      "dev": true
-    },
-    "di": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
-      "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
-      "dev": true
-    },
-    "diff": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
-      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
-      "dev": true
-    },
-    "diffie-hellman": {
-      "version": "5.0.3",
-      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
-      "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.1.0",
-        "miller-rabin": "^4.0.0",
-        "randombytes": "^2.0.0"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "dir-glob": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
-      "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
-      "dev": true,
-      "requires": {
-        "path-type": "^3.0.0"
-      }
-    },
-    "dns-equal": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
-      "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
-      "dev": true
-    },
-    "dns-packet": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
-      "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
-      "dev": true,
-      "requires": {
-        "ip": "^1.1.0",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "dns-txt": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
-      "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
-      "dev": true,
-      "requires": {
-        "buffer-indexof": "^1.0.0"
-      }
-    },
-    "doctrine": {
-      "version": "0.7.2",
-      "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz",
-      "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=",
-      "dev": true,
-      "requires": {
-        "esutils": "^1.1.6",
-        "isarray": "0.0.1"
-      },
-      "dependencies": {
-        "esutils": {
-          "version": "1.1.6",
-          "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz",
-          "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=",
-          "dev": true
-        },
-        "isarray": {
-          "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
-          "dev": true
-        }
-      }
-    },
-    "dom-serialize": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
-      "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
-      "dev": true,
-      "requires": {
-        "custom-event": "~1.0.0",
-        "ent": "~2.2.0",
-        "extend": "^3.0.0",
-        "void-elements": "^2.0.0"
-      }
-    },
-    "domain-browser": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
-      "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
-      "dev": true
-    },
-    "duplexify": {
-      "version": "3.7.1",
-      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
-      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.0.0",
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.0.0",
-        "stream-shift": "^1.0.0"
-      }
-    },
-    "ecc-jsbn": {
-      "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"
-      }
-    },
-    "ee-first": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
-      "dev": true
-    },
-    "electron-to-chromium": {
-      "version": "1.3.603",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.603.tgz",
-      "integrity": "sha512-J8OHxOeJkoSLgBXfV9BHgKccgfLMHh+CoeRo6wJsi6m0k3otaxS/5vrHpMNSEYY4MISwewqanPOuhAtuE8riQQ==",
-      "dev": true
-    },
-    "elliptic": {
-      "version": "6.5.3",
-      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
-      "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.4.0",
-        "brorand": "^1.0.1",
-        "hash.js": "^1.0.0",
-        "hmac-drbg": "^1.0.0",
-        "inherits": "^2.0.1",
-        "minimalistic-assert": "^1.0.0",
-        "minimalistic-crypto-utils": "^1.0.0"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "emojis-list": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
-      "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
-      "dev": true
-    },
-    "encodeurl": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
-      "dev": true
-    },
-    "encoding": {
-      "version": "0.1.13",
-      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
-      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
-      "dev": true,
-      "requires": {
-        "iconv-lite": "^0.6.2"
-      },
-      "dependencies": {
-        "iconv-lite": {
-          "version": "0.6.2",
-          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
-          "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
-          "dev": true,
-          "requires": {
-            "safer-buffer": ">= 2.1.2 < 3.0.0"
-          }
-        }
-      }
-    },
-    "end-of-stream": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
-      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
-      "dev": true,
-      "requires": {
-        "once": "^1.4.0"
-      }
-    },
-    "engine.io": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz",
-      "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==",
-      "dev": true,
-      "requires": {
-        "accepts": "~1.3.4",
-        "base64id": "1.0.0",
-        "cookie": "0.3.1",
-        "debug": "~3.1.0",
-        "engine.io-parser": "~2.1.0",
-        "ws": "~3.3.1"
-      },
-      "dependencies": {
-        "cookie": {
-          "version": "0.3.1",
-          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
-          "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
-          "dev": true
-        },
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        }
-      }
-    },
-    "engine.io-client": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
-      "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
-      "dev": true,
-      "requires": {
-        "component-emitter": "1.2.1",
-        "component-inherit": "0.0.3",
-        "debug": "~3.1.0",
-        "engine.io-parser": "~2.1.1",
-        "has-cors": "1.1.0",
-        "indexof": "0.0.1",
-        "parseqs": "0.0.5",
-        "parseuri": "0.0.5",
-        "ws": "~3.3.1",
-        "xmlhttprequest-ssl": "~1.5.4",
-        "yeast": "0.1.2"
-      },
-      "dependencies": {
-        "component-emitter": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
-          "dev": true
-        },
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        }
-      }
-    },
-    "engine.io-parser": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz",
-      "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==",
-      "dev": true,
-      "requires": {
-        "after": "0.8.2",
-        "arraybuffer.slice": "~0.0.7",
-        "base64-arraybuffer": "0.1.5",
-        "blob": "0.0.5",
-        "has-binary2": "~1.0.2"
-      }
-    },
-    "enhanced-resolve": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz",
-      "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "memory-fs": "^0.4.0",
-        "tapable": "^1.0.0"
-      }
-    },
-    "ent": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
-      "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
-      "dev": true
-    },
-    "err-code": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
-      "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=",
-      "dev": true
-    },
-    "errno": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
-      "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
-      "dev": true,
-      "requires": {
-        "prr": "~1.0.1"
-      }
-    },
-    "error-ex": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
-      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
-      "dev": true,
-      "requires": {
-        "is-arrayish": "^0.2.1"
-      }
-    },
-    "es-abstract": {
-      "version": "1.18.0-next.1",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
-      "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
-      "dev": true,
-      "requires": {
-        "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1",
-        "is-callable": "^1.2.2",
-        "is-negative-zero": "^2.0.0",
-        "is-regex": "^1.1.1",
-        "object-inspect": "^1.8.0",
-        "object-keys": "^1.1.1",
-        "object.assign": "^4.1.1",
-        "string.prototype.trimend": "^1.0.1",
-        "string.prototype.trimstart": "^1.0.1"
-      }
-    },
-    "es-to-primitive": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
-      "dev": true,
-      "requires": {
-        "is-callable": "^1.1.4",
-        "is-date-object": "^1.0.1",
-        "is-symbol": "^1.0.2"
-      }
-    },
-    "es6-promise": {
-      "version": "4.2.8",
-      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
-      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
-      "dev": true
-    },
-    "es6-promisify": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
-      "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
-      "dev": true,
-      "requires": {
-        "es6-promise": "^4.0.3"
-      }
-    },
-    "escalade": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-      "dev": true
-    },
-    "escape-html": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
-      "dev": true
-    },
-    "escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true
-    },
-    "eslint-scope": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
-      "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
-      "dev": true,
-      "requires": {
-        "esrecurse": "^4.1.0",
-        "estraverse": "^4.1.1"
-      }
-    },
-    "esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true
-    },
-    "esrecurse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
-      "dev": true,
-      "requires": {
-        "estraverse": "^5.2.0"
-      },
-      "dependencies": {
-        "estraverse": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
-          "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
-          "dev": true
-        }
-      }
-    },
-    "estraverse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
-      "dev": true
-    },
-    "esutils": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-      "dev": true
-    },
-    "etag": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
-      "dev": true
-    },
-    "eventemitter3": {
-      "version": "4.0.7",
-      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
-      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
-      "dev": true
-    },
-    "events": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
-      "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
-      "dev": true
-    },
-    "eventsource": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz",
-      "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==",
-      "dev": true,
-      "requires": {
-        "original": "^1.0.0"
-      }
-    },
-    "evp_bytestokey": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
-      "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
-      "dev": true,
-      "requires": {
-        "md5.js": "^1.3.4",
-        "safe-buffer": "^5.1.1"
-      }
-    },
-    "execa": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz",
-      "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==",
-      "dev": true,
-      "requires": {
-        "cross-spawn": "^6.0.0",
-        "get-stream": "^3.0.0",
-        "is-stream": "^1.1.0",
-        "npm-run-path": "^2.0.0",
-        "p-finally": "^1.0.0",
-        "signal-exit": "^3.0.0",
-        "strip-eof": "^1.0.0"
-      },
-      "dependencies": {
-        "cross-spawn": {
-          "version": "6.0.5",
-          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
-          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
-          "dev": true,
-          "requires": {
-            "nice-try": "^1.0.4",
-            "path-key": "^2.0.1",
-            "semver": "^5.5.0",
-            "shebang-command": "^1.2.0",
-            "which": "^1.2.9"
-          }
-        }
-      }
-    },
-    "exit": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
-      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
-      "dev": true
-    },
-    "expand-brackets": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
-      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
-      "dev": true,
-      "requires": {
-        "debug": "^2.3.3",
-        "define-property": "^0.2.5",
-        "extend-shallow": "^2.0.1",
-        "posix-character-classes": "^0.1.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "express": {
-      "version": "4.17.1",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
-      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
-      "dev": true,
-      "requires": {
-        "accepts": "~1.3.7",
-        "array-flatten": "1.1.1",
-        "body-parser": "1.19.0",
-        "content-disposition": "0.5.3",
-        "content-type": "~1.0.4",
-        "cookie": "0.4.0",
-        "cookie-signature": "1.0.6",
-        "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "etag": "~1.8.1",
-        "finalhandler": "~1.1.2",
-        "fresh": "0.5.2",
-        "merge-descriptors": "1.0.1",
-        "methods": "~1.1.2",
-        "on-finished": "~2.3.0",
-        "parseurl": "~1.3.3",
-        "path-to-regexp": "0.1.7",
-        "proxy-addr": "~2.0.5",
-        "qs": "6.7.0",
-        "range-parser": "~1.2.1",
-        "safe-buffer": "5.1.2",
-        "send": "0.17.1",
-        "serve-static": "1.14.1",
-        "setprototypeof": "1.1.1",
-        "statuses": "~1.5.0",
-        "type-is": "~1.6.18",
-        "utils-merge": "1.0.1",
-        "vary": "~1.1.2"
-      },
-      "dependencies": {
-        "array-flatten": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
-          "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
-          "dev": true
-        },
-        "qs": {
-          "version": "6.7.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
-          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
-          "dev": true
-        }
-      }
-    },
-    "extend": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
-      "dev": true
-    },
-    "extend-shallow": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
-      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
-      "dev": true,
-      "requires": {
-        "assign-symbols": "^1.0.0",
-        "is-extendable": "^1.0.1"
-      },
-      "dependencies": {
-        "is-extendable": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
-          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
-          "dev": true,
-          "requires": {
-            "is-plain-object": "^2.0.4"
-          }
-        }
-      }
-    },
-    "external-editor": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
-      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
-      "dev": true,
-      "requires": {
-        "chardet": "^0.7.0",
-        "iconv-lite": "^0.4.24",
-        "tmp": "^0.0.33"
-      }
-    },
-    "extglob": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
-      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
-      "dev": true,
-      "requires": {
-        "array-unique": "^0.3.2",
-        "define-property": "^1.0.0",
-        "expand-brackets": "^2.1.4",
-        "extend-shallow": "^2.0.1",
-        "fragment-cache": "^0.2.1",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
-    "extsprintf": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
-      "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=",
-      "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=",
-      "dev": true
-    },
-    "fastparse": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
-      "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
-      "dev": true
-    },
-    "faye-websocket": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
-      "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
-      "dev": true,
-      "requires": {
-        "websocket-driver": ">=0.5.1"
-      }
-    },
-    "figgy-pudding": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
-      "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==",
-      "dev": true
-    },
-    "figures": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
-      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
-      "dev": true,
-      "requires": {
-        "escape-string-regexp": "^1.0.5"
-      }
-    },
-    "file-loader": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz",
-      "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.0.2",
-        "schema-utils": "^1.0.0"
-      }
-    },
-    "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",
-      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
-      "dev": true,
-      "optional": true
-    },
-    "fileset": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
-      "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=",
-      "dev": true,
-      "requires": {
-        "glob": "^7.0.3",
-        "minimatch": "^3.0.3"
-      }
-    },
-    "fill-range": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^2.0.1",
-        "is-number": "^3.0.0",
-        "repeat-string": "^1.6.1",
-        "to-regex-range": "^2.1.0"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "finalhandler": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
-      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
-      "dev": true,
-      "requires": {
-        "debug": "2.6.9",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "on-finished": "~2.3.0",
-        "parseurl": "~1.3.3",
-        "statuses": "~1.5.0",
-        "unpipe": "~1.0.0"
-      }
-    },
-    "find-cache-dir": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
-      "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=",
-      "dev": true,
-      "requires": {
-        "commondir": "^1.0.1",
-        "make-dir": "^1.0.0",
-        "pkg-dir": "^2.0.0"
-      }
-    },
-    "find-up": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-      "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
-      "dev": true,
-      "requires": {
-        "locate-path": "^2.0.0"
-      }
-    },
-    "flatted": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
-      "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
-      "dev": true
-    },
-    "flush-write-stream": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
-      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.3.6"
-      }
-    },
-    "follow-redirects": {
-      "version": "1.13.0",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
-      "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==",
-      "dev": true
-    },
-    "font-awesome": {
-      "version": "4.7.0",
-      "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
-      "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
-    },
-    "for-in": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
-      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
-      "dev": true
-    },
-    "for-own": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
-      "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
-      "dev": true,
-      "requires": {
-        "for-in": "^1.0.1"
-      }
-    },
-    "forever-agent": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-      "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",
-        "mime-types": "^2.1.12"
-      }
-    },
-    "forwarded": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
-      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
-      "dev": true
-    },
-    "fragment-cache": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
-      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
-      "dev": true,
-      "requires": {
-        "map-cache": "^0.2.2"
-      }
-    },
-    "fresh": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
-      "dev": true
-    },
-    "from2": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
-      "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.0.0"
-      }
-    },
-    "fs-extra": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
-      "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "jsonfile": "^4.0.0",
-        "universalify": "^0.1.0"
-      }
-    },
-    "fs-minipass": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
-      "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
-      "dev": true,
-      "requires": {
-        "minipass": "^2.6.0"
-      }
-    },
-    "fs-write-stream-atomic": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
-      "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "iferr": "^0.1.5",
-        "imurmurhash": "^0.1.4",
-        "readable-stream": "1 || 2"
-      }
-    },
-    "fs.realpath": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-      "dev": true
-    },
-    "fsevents": {
-      "version": "1.2.13",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-      "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "bindings": "^1.5.0",
-        "nan": "^2.12.1"
-      }
-    },
-    "fstream": {
-      "version": "1.0.12",
-      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
-      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "inherits": "~2.0.0",
-        "mkdirp": ">=0.5 0",
-        "rimraf": "2"
-      }
-    },
-    "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
-    },
-    "gauge": {
-      "version": "2.7.4",
-      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
-      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
-      "dev": true,
-      "requires": {
-        "aproba": "^1.0.3",
-        "console-control-strings": "^1.0.0",
-        "has-unicode": "^2.0.0",
-        "object-assign": "^4.1.0",
-        "signal-exit": "^3.0.0",
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1",
-        "wide-align": "^1.1.0"
-      }
-    },
-    "gaze": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
-      "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "globule": "^1.0.0"
-      }
-    },
-    "genfun": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
-      "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==",
-      "dev": true
-    },
-    "get-caller-file": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
-      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
-      "dev": true
-    },
-    "get-intrinsic": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz",
-      "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
-      }
-    },
-    "get-stdin": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
-      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
-      "dev": true
-    },
-    "get-stream": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-      "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
-      "dev": true
-    },
-    "get-value": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
-      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
-      "dev": true
-    },
-    "getpass": {
-      "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.3",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
-      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
-      "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"
-      }
-    },
-    "glob-parent": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
-      "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
-      "dev": true,
-      "requires": {
-        "is-glob": "^3.1.0",
-        "path-dirname": "^1.0.0"
-      },
-      "dependencies": {
-        "is-glob": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.0"
-          }
-        }
-      }
-    },
-    "globals": {
-      "version": "11.12.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-      "dev": true
-    },
-    "globby": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
-      "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
-      "dev": true,
-      "requires": {
-        "array-union": "^1.0.1",
-        "dir-glob": "^2.0.0",
-        "glob": "^7.1.2",
-        "ignore": "^3.3.5",
-        "pify": "^3.0.0",
-        "slash": "^1.0.0"
-      }
-    },
-    "globule": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
-      "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "glob": "~7.1.1",
-        "lodash": "~4.17.10",
-        "minimatch": "~3.0.2"
-      }
-    },
-    "good-listener": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
-      "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
-      "optional": true,
-      "requires": {
-        "delegate": "^3.1.2"
-      }
-    },
-    "graceful-fs": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
-      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
-      "dev": true
-    },
-    "handle-thing": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
-      "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
-      "dev": true
-    },
-    "har-schema": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
-      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
-      "dev": true
-    },
-    "har-validator": {
-      "version": "5.1.5",
-      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
-      "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
-      "dev": true,
-      "requires": {
-        "ajv": "^6.12.3",
-        "har-schema": "^2.0.0"
-      },
-      "dependencies": {
-        "ajv": {
-          "version": "6.12.6",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-          "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-          "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.3",
-          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-          "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-          "dev": true
-        }
-      }
-    },
-    "has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1"
-      }
-    },
-    "has-ansi": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
-      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
-      "dev": true,
-      "requires": {
-        "ansi-regex": "^2.0.0"
-      }
-    },
-    "has-binary2": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
-      "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
-      "dev": true,
-      "requires": {
-        "isarray": "2.0.1"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
-          "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
-          "dev": true
-        }
-      }
-    },
-    "has-cors": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
-      "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
-      "dev": true
-    },
-    "has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
-    },
-    "has-symbols": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
-      "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
-      "dev": true
-    },
-    "has-unicode": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
-      "dev": true
-    },
-    "has-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
-      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
-      "dev": true,
-      "requires": {
-        "get-value": "^2.0.6",
-        "has-values": "^1.0.0",
-        "isobject": "^3.0.0"
-      }
-    },
-    "has-values": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
-      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
-      "dev": true,
-      "requires": {
-        "is-number": "^3.0.0",
-        "kind-of": "^4.0.0"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
-          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "hash-base": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
-      "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.4",
-        "readable-stream": "^3.6.0",
-        "safe-buffer": "^5.2.0"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-          "dev": true
-        },
-        "readable-stream": {
-          "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",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.2.1",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-          "dev": true
-        }
-      }
-    },
-    "hash.js": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
-      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "minimalistic-assert": "^1.0.1"
-      }
-    },
-    "hmac-drbg": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
-      "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
-      "dev": true,
-      "requires": {
-        "hash.js": "^1.0.3",
-        "minimalistic-assert": "^1.0.0",
-        "minimalistic-crypto-utils": "^1.0.1"
-      }
-    },
-    "hosted-git-info": {
-      "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": {
-      "version": "2.1.6",
-      "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
-      "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "obuf": "^1.0.0",
-        "readable-stream": "^2.0.1",
-        "wbuf": "^1.1.0"
-      }
-    },
-    "html-entities": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz",
-      "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==",
-      "dev": true
-    },
-    "html-escaper": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
-      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
-      "dev": true
-    },
-    "http-cache-semantics": {
-      "version": "3.8.1",
-      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
-      "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
-      "dev": true
-    },
-    "http-deceiver": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
-      "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=",
-      "dev": true
-    },
-    "http-errors": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
-      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
-      "dev": true,
-      "requires": {
-        "depd": "~1.1.2",
-        "inherits": "2.0.3",
-        "setprototypeof": "1.1.1",
-        "statuses": ">= 1.5.0 < 2",
-        "toidentifier": "1.0.0"
-      }
-    },
-    "http-parser-js": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz",
-      "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==",
-      "dev": true
-    },
-    "http-proxy": {
-      "version": "1.18.1",
-      "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
-      "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
-      "dev": true,
-      "requires": {
-        "eventemitter3": "^4.0.0",
-        "follow-redirects": "^1.0.0",
-        "requires-port": "^1.0.0"
-      }
-    },
-    "http-proxy-agent": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
-      "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
-      "dev": true,
-      "requires": {
-        "agent-base": "4",
-        "debug": "3.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        }
-      }
-    },
-    "http-proxy-middleware": {
-      "version": "0.18.0",
-      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz",
-      "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==",
-      "dev": true,
-      "requires": {
-        "http-proxy": "^1.16.2",
-        "is-glob": "^4.0.0",
-        "lodash": "^4.17.5",
-        "micromatch": "^3.1.9"
-      }
-    },
-    "http-signature": {
-      "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",
-        "sshpk": "^1.7.0"
-      }
-    },
-    "https-browserify": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
-      "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
-      "dev": true
-    },
-    "https-proxy-agent": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
-      "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
-      "dev": true,
-      "requires": {
-        "agent-base": "^4.3.0",
-        "debug": "^3.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.7",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-          "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
-        }
-      }
-    },
-    "humanize-ms": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
-      "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
-      "dev": true,
-      "requires": {
-        "ms": "^2.0.0"
-      }
-    },
-    "iconv-lite": {
-      "version": "0.4.24",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-      "dev": true,
-      "requires": {
-        "safer-buffer": ">= 2.1.2 < 3"
-      }
-    },
-    "ieee754": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-      "dev": true
-    },
-    "iferr": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-      "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
-      "dev": true
-    },
-    "ignore": {
-      "version": "3.3.10",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
-      "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
-      "dev": true
-    },
-    "ignore-walk": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
-      "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
-      "dev": true,
-      "requires": {
-        "minimatch": "^3.0.4"
-      }
-    },
-    "image-size": {
-      "version": "0.5.5",
-      "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
-      "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
-      "dev": true,
-      "optional": true
-    },
-    "immediate": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
-      "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=",
-      "dev": true
-    },
-    "import-cwd": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
-      "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
-      "dev": true,
-      "requires": {
-        "import-from": "^2.1.0"
-      }
-    },
-    "import-fresh": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
-      "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
-      "dev": true,
-      "requires": {
-        "caller-path": "^2.0.0",
-        "resolve-from": "^3.0.0"
-      }
-    },
-    "import-from": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
-      "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
-      "dev": true,
-      "requires": {
-        "resolve-from": "^3.0.0"
-      }
-    },
-    "import-local": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
-      "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
-      "dev": true,
-      "requires": {
-        "pkg-dir": "^3.0.0",
-        "resolve-cwd": "^2.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^3.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^3.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "p-limit": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.0.0"
-          }
-        },
-        "p-try": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-          "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-          "dev": true
-        },
-        "pkg-dir": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
-          "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
-          "dev": true,
-          "requires": {
-            "find-up": "^3.0.0"
-          }
-        }
-      }
-    },
-    "imurmurhash": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
-      "dev": true
-    },
-    "in-publish": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
-      "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
-      "dev": true,
-      "optional": true
-    },
-    "indent-string": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "repeating": "^2.0.0"
-      }
-    },
-    "indexof": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
-      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
-      "dev": true
-    },
-    "inflight": {
-      "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"
-      }
-    },
-    "inherits": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-      "dev": true
-    },
-    "ini": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
-      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
-      "dev": true
-    },
-    "inquirer": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
-      "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
-      "dev": true,
-      "requires": {
-        "ansi-escapes": "^3.0.0",
-        "chalk": "^2.0.0",
-        "cli-cursor": "^2.1.0",
-        "cli-width": "^2.0.0",
-        "external-editor": "^3.0.0",
-        "figures": "^2.0.0",
-        "lodash": "^4.17.10",
-        "mute-stream": "0.0.7",
-        "run-async": "^2.2.0",
-        "rxjs": "^6.1.0",
-        "string-width": "^2.1.0",
-        "strip-ansi": "^5.0.0",
-        "through": "^2.3.6"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-          "dev": true,
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          },
-          "dependencies": {
-            "strip-ansi": {
-              "version": "4.0.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-              "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-              "dev": true,
-              "requires": {
-                "ansi-regex": "^3.0.0"
-              }
-            }
-          }
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          },
-          "dependencies": {
-            "ansi-regex": {
-              "version": "4.1.0",
-              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-              "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-              "dev": true
-            }
-          }
-        }
-      }
-    },
-    "internal-ip": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz",
-      "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==",
-      "dev": true,
-      "requires": {
-        "default-gateway": "^2.6.0",
-        "ipaddr.js": "^1.5.2"
-      }
-    },
-    "interpret": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
-      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
-      "dev": true
-    },
-    "invariant": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
-      "dev": true,
-      "requires": {
-        "loose-envify": "^1.0.0"
-      }
-    },
-    "invert-kv": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
-      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
-      "dev": true
-    },
-    "ip": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
-      "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
-      "dev": true
-    },
-    "ip-regex": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
-      "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
-      "dev": true
-    },
-    "ipaddr.js": {
-      "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
-    },
-    "is-accessor-descriptor": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
-      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "is-arguments": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
-      "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
-      "dev": true
-    },
-    "is-arrayish": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
-      "dev": true
-    },
-    "is-binary-path": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
-      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
-      "dev": true,
-      "requires": {
-        "binary-extensions": "^1.0.0"
-      }
-    },
-    "is-buffer": {
-      "version": "1.1.6",
-      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
-      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
-      "dev": true
-    },
-    "is-callable": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
-      "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
-      "dev": true
-    },
-    "is-core-module": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz",
-      "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.3"
-      }
-    },
-    "is-data-descriptor": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
-      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "is-date-object": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
-      "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
-      "dev": true
-    },
-    "is-descriptor": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
-      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
-      "dev": true,
-      "requires": {
-        "is-accessor-descriptor": "^0.1.6",
-        "is-data-descriptor": "^0.1.4",
-        "kind-of": "^5.0.0"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-          "dev": true
-        }
-      }
-    },
-    "is-directory": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
-      "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
-      "dev": true
-    },
-    "is-docker": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
-      "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
-      "dev": true
-    },
-    "is-extendable": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
-      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
-      "dev": true
-    },
-    "is-extglob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-      "dev": true
-    },
-    "is-finite": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
-      "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
-      "dev": true
-    },
-    "is-fullwidth-code-point": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
-      "dev": true,
-      "requires": {
-        "number-is-nan": "^1.0.0"
-      }
-    },
-    "is-glob": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-      "dev": true,
-      "requires": {
-        "is-extglob": "^2.1.1"
-      }
-    },
-    "is-negative-zero": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
-      "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
-      "dev": true
-    },
-    "is-number": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "is-path-cwd": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
-      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
-      "dev": true
-    },
-    "is-path-in-cwd": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
-      "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
-      "dev": true,
-      "requires": {
-        "is-path-inside": "^1.0.0"
-      }
-    },
-    "is-path-inside": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
-      "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
-      "dev": true,
-      "requires": {
-        "path-is-inside": "^1.0.1"
-      }
-    },
-    "is-plain-object": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
-      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.1"
-      }
-    },
-    "is-regex": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
-      "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
-      "dev": true,
-      "requires": {
-        "has-symbols": "^1.0.1"
-      }
-    },
-    "is-stream": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
-      "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
-      "dev": true
-    },
-    "is-symbol": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
-      "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
-      "dev": true,
-      "requires": {
-        "has-symbols": "^1.0.1"
-      }
-    },
-    "is-typedarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
-      "dev": true
-    },
-    "is-utf8": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
-      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
-      "dev": true
-    },
-    "is-windows": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
-      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
-      "dev": true
-    },
-    "is-wsl": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
-      "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
-      "dev": true
-    },
-    "isarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-      "dev": true
-    },
-    "isbinaryfile": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz",
-      "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==",
-      "dev": true,
-      "requires": {
-        "buffer-alloc": "^1.2.0"
-      }
-    },
-    "isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
-      "dev": true
-    },
-    "isobject": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-      "dev": true
-    },
-    "isstream": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
-      "dev": true
-    },
-    "istanbul-api": {
-      "version": "2.1.7",
-      "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.7.tgz",
-      "integrity": "sha512-LYTOa2UrYFyJ/aSczZi/6lBykVMjCCvUmT64gOe+jPZFy4w6FYfPGqFT2IiQ2BxVHHDOvCD7qrIXb0EOh4uGWw==",
-      "dev": true,
-      "requires": {
-        "async": "^2.6.2",
-        "compare-versions": "^3.4.0",
-        "fileset": "^2.0.3",
-        "istanbul-lib-coverage": "^2.0.5",
-        "istanbul-lib-hook": "^2.0.7",
-        "istanbul-lib-instrument": "^3.3.0",
-        "istanbul-lib-report": "^2.0.8",
-        "istanbul-lib-source-maps": "^3.0.6",
-        "istanbul-reports": "^2.2.5",
-        "js-yaml": "^3.13.1",
-        "make-dir": "^2.1.0",
-        "minimatch": "^3.0.4",
-        "once": "^1.4.0"
-      },
-      "dependencies": {
-        "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
-        },
-        "istanbul-lib-instrument": {
-          "version": "3.3.0",
-          "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz",
-          "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==",
-          "dev": true,
-          "requires": {
-            "@babel/generator": "^7.4.0",
-            "@babel/parser": "^7.4.3",
-            "@babel/template": "^7.4.0",
-            "@babel/traverse": "^7.4.3",
-            "@babel/types": "^7.4.0",
-            "istanbul-lib-coverage": "^2.0.5",
-            "semver": "^6.0.0"
-          }
-        },
-        "make-dir": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
-          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
-          "dev": true,
-          "requires": {
-            "pify": "^4.0.1",
-            "semver": "^5.6.0"
-          },
-          "dependencies": {
-            "semver": {
-              "version": "5.7.1",
-              "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-              "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-              "dev": true
-            }
-          }
-        },
-        "pify": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
-          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
-          "dev": true
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
-    },
-    "istanbul-instrumenter-loader": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz",
-      "integrity": "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w==",
-      "dev": true,
-      "requires": {
-        "convert-source-map": "^1.5.0",
-        "istanbul-lib-instrument": "^1.7.3",
-        "loader-utils": "^1.1.0",
-        "schema-utils": "^0.3.0"
-      },
-      "dependencies": {
-        "ajv": {
-          "version": "5.5.2",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
-          "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
-          "dev": true,
-          "requires": {
-            "co": "^4.6.0",
-            "fast-deep-equal": "^1.0.0",
-            "fast-json-stable-stringify": "^2.0.0",
-            "json-schema-traverse": "^0.3.0"
-          }
-        },
-        "fast-deep-equal": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
-          "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
-          "dev": true
-        },
-        "json-schema-traverse": {
-          "version": "0.3.1",
-          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
-          "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
-          "dev": true
-        },
-        "schema-utils": {
-          "version": "0.3.0",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
-          "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
-          "dev": true,
-          "requires": {
-            "ajv": "^5.0.0"
-          }
-        }
-      }
-    },
-    "istanbul-lib-coverage": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz",
-      "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==",
-      "dev": true
-    },
-    "istanbul-lib-hook": {
-      "version": "2.0.7",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz",
-      "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==",
-      "dev": true,
-      "requires": {
-        "append-transform": "^1.0.0"
-      }
-    },
-    "istanbul-lib-instrument": {
-      "version": "1.10.2",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz",
-      "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==",
-      "dev": true,
-      "requires": {
-        "babel-generator": "^6.18.0",
-        "babel-template": "^6.16.0",
-        "babel-traverse": "^6.18.0",
-        "babel-types": "^6.18.0",
-        "babylon": "^6.18.0",
-        "istanbul-lib-coverage": "^1.2.1",
-        "semver": "^5.3.0"
-      }
-    },
-    "istanbul-lib-report": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz",
-      "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==",
-      "dev": true,
-      "requires": {
-        "istanbul-lib-coverage": "^2.0.5",
-        "make-dir": "^2.1.0",
-        "supports-color": "^6.1.0"
-      },
-      "dependencies": {
-        "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
-        },
-        "make-dir": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
-          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
-          "dev": true,
-          "requires": {
-            "pify": "^4.0.1",
-            "semver": "^5.6.0"
-          }
-        },
-        "pify": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
-          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
-          "dev": true
-        }
-      }
-    },
-    "istanbul-lib-source-maps": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz",
-      "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==",
-      "dev": true,
-      "requires": {
-        "debug": "^4.1.1",
-        "istanbul-lib-coverage": "^2.0.5",
-        "make-dir": "^2.1.0",
-        "rimraf": "^2.6.3",
-        "source-map": "^0.6.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "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
-        },
-        "make-dir": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
-          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
-          "dev": true,
-          "requires": {
-            "pify": "^4.0.1",
-            "semver": "^5.6.0"
-          }
-        },
-        "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
-        },
-        "pify": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
-          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "istanbul-reports": {
-      "version": "2.2.7",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz",
-      "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==",
-      "dev": true,
-      "requires": {
-        "html-escaper": "^2.0.0"
-      }
-    },
-    "jasmine": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz",
-      "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=",
-      "dev": true,
-      "requires": {
-        "exit": "^0.1.2",
-        "glob": "^7.0.6",
-        "jasmine-core": "~2.8.0"
-      },
-      "dependencies": {
-        "jasmine-core": {
-          "version": "2.8.0",
-          "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz",
-          "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=",
-          "dev": true
-        }
-      }
-    },
-    "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-spec-reporter": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.1.tgz",
-      "integrity": "sha512-RrOZ+bSPnbk1/9KKs5lm0Nl0cqDCh/XXVlCmu3nkhEJH6HTDh4hoJZu3q8e9aq37C0eXEf/JEJnYy+t4m3arZQ==",
-      "dev": true,
-      "requires": {
-        "colors": "1.4.0"
-      }
-    },
-    "jasminewd2": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz",
-      "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=",
-      "dev": true
-    },
-    "jquery": {
-      "version": "3.5.1",
-      "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
-      "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
-    },
-    "js-base64": {
-      "version": "2.6.4",
-      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
-      "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
-      "dev": true,
-      "optional": true
-    },
-    "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
-    },
-    "js-yaml": {
-      "version": "3.14.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
-      "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
-      "dev": true,
-      "requires": {
-        "argparse": "^1.0.7",
-        "esprima": "^4.0.0"
-      }
-    },
-    "jsbn": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
-      "dev": true
-    },
-    "jsesc": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-      "dev": true
-    },
-    "json-parse-better-errors": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
-      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
-      "dev": true
-    },
-    "json-schema": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
-      "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==",
-      "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=",
-      "dev": true
-    },
-    "json3": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
-      "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==",
-      "dev": true
-    },
-    "json5": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-      "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-      "dev": true,
-      "requires": {
-        "minimist": "^1.2.0"
-      }
-    },
-    "jsonfile": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
-      "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.6"
-      }
-    },
-    "jsonparse": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
-      "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
-      "dev": true
-    },
-    "jsprim": {
-      "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",
-        "json-schema": "0.2.3",
-        "verror": "1.10.0"
-      }
-    },
-    "jstree": {
-      "version": "3.3.5",
-      "resolved": "https://registry.npmjs.org/jstree/-/jstree-3.3.5.tgz",
-      "integrity": "sha1-nFeNsy0KZDd1zd2AIK1ZkvQRnBM=",
-      "requires": {
-        "jquery": ">=1.9.1"
-      }
-    },
-    "jszip": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz",
-      "integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==",
-      "dev": true,
-      "requires": {
-        "lie": "~3.3.0",
-        "pako": "~1.0.2",
-        "readable-stream": "~2.3.6",
-        "set-immediate-shim": "~1.0.1"
-      }
-    },
-    "karma": {
-      "version": "4.4.1",
-      "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz",
-      "integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==",
-      "dev": true,
-      "requires": {
-        "bluebird": "^3.3.0",
-        "body-parser": "^1.16.1",
-        "braces": "^3.0.2",
-        "chokidar": "^3.0.0",
-        "colors": "^1.1.0",
-        "connect": "^3.6.0",
-        "di": "^0.0.1",
-        "dom-serialize": "^2.2.0",
-        "flatted": "^2.0.0",
-        "glob": "^7.1.1",
-        "graceful-fs": "^4.1.2",
-        "http-proxy": "^1.13.0",
-        "isbinaryfile": "^3.0.0",
-        "lodash": "^4.17.14",
-        "log4js": "^4.0.0",
-        "mime": "^2.3.1",
-        "minimatch": "^3.0.2",
-        "optimist": "^0.6.1",
-        "qjobs": "^1.1.4",
-        "range-parser": "^1.2.0",
-        "rimraf": "^2.6.0",
-        "safe-buffer": "^5.0.1",
-        "socket.io": "2.1.1",
-        "source-map": "^0.6.1",
-        "tmp": "0.0.33",
-        "useragent": "2.3.0"
-      },
-      "dependencies": {
-        "anymatch": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
-          "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
-          "dev": true,
-          "requires": {
-            "normalize-path": "^3.0.0",
-            "picomatch": "^2.0.4"
-          }
-        },
-        "binary-extensions": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
-          "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
-          "dev": true
-        },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "chokidar": {
-          "version": "3.4.3",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
-          "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
-          "dev": true,
-          "requires": {
-            "anymatch": "~3.1.1",
-            "braces": "~3.0.2",
-            "fsevents": "~2.1.2",
-            "glob-parent": "~5.1.0",
-            "is-binary-path": "~2.1.0",
-            "is-glob": "~4.0.1",
-            "normalize-path": "~3.0.0",
-            "readdirp": "~3.5.0"
-          }
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "fsevents": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
-          "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
-          "dev": true,
-          "optional": true
-        },
-        "glob-parent": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
-          "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
-          "dev": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        },
-        "is-binary-path": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-          "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-          "dev": true,
-          "requires": {
-            "binary-extensions": "^2.0.0"
-          }
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "mime": {
-          "version": "2.4.6",
-          "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
-          "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
-          "dev": true
-        },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-          "dev": true
-        },
-        "readdirp": {
-          "version": "3.5.0",
-          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
-          "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
-          "dev": true,
-          "requires": {
-            "picomatch": "^2.2.1"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-          "dev": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
-        }
-      }
-    },
-    "karma-chrome-launcher": {
-      "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": {
-        "which": "^1.2.1"
-      }
-    },
-    "karma-coverage-istanbul-reporter": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.1.1.tgz",
-      "integrity": "sha512-CH8lTi8+kKXGvrhy94+EkEMldLCiUA0xMOiL31vvli9qK0T+qcXJAwWBRVJWnVWxYkTmyWar8lPz63dxX6/z1A==",
-      "dev": true,
-      "requires": {
-        "istanbul-api": "^2.1.6",
-        "minimatch": "^3.0.4"
-      }
-    },
-    "karma-firefox-launcher": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.3.0.tgz",
-      "integrity": "sha512-Fi7xPhwrRgr+94BnHX0F5dCl1miIW4RHnzjIGxF8GaIEp7rNqX7LSi7ok63VXs3PS/5MQaQMhGxw+bvD+pibBQ==",
-      "dev": true,
-      "requires": {
-        "is-wsl": "^2.1.0"
-      },
-      "dependencies": {
-        "is-wsl": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
-          "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
-          "dev": true,
-          "requires": {
-            "is-docker": "^2.0.0"
-          }
-        }
-      }
-    },
-    "karma-jasmine": {
-      "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.5.0"
-      }
-    },
-    "karma-jasmine-html-reporter": {
-      "version": "1.5.3",
-      "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.3.tgz",
-      "integrity": "sha512-ci0VrjuCaFj+9d1tYlTE3KIPUCp0rz874zWWU3JgCMqGIyw5ke+BXWFPOAGAqUdCJcrMwneyvp1zFXA74MiPUA==",
-      "dev": true
-    },
-    "karma-junit-reporter": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-2.0.1.tgz",
-      "integrity": "sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==",
-      "dev": true,
-      "requires": {
-        "path-is-absolute": "^1.0.0",
-        "xmlbuilder": "12.0.0"
-      }
-    },
-    "karma-source-map-support": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz",
-      "integrity": "sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q==",
-      "dev": true,
-      "requires": {
-        "source-map-support": "^0.5.5"
-      }
-    },
-    "katex": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz",
-      "integrity": "sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww==",
-      "requires": {
-        "commander": "^2.19.0"
-      },
-      "dependencies": {
-        "commander": {
-          "version": "2.20.3",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
-        }
-      }
-    },
-    "killable": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
-      "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==",
-      "dev": true
-    },
-    "kind-of": {
-      "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": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
-      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
-      "dev": true,
-      "requires": {
-        "invert-kv": "^1.0.0"
-      }
-    },
-    "leaflet": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.3.4.tgz",
-      "integrity": "sha512-FYL1LGFdj6v+2Ifpw+AcFIuIOqjNggfoLUwuwQv6+3sS21Za7Wvapq+LhbSE4NDXrEj6eYnW3y7LsaBICpyXtw=="
-    },
-    "leaflet.markercluster": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.4.1.tgz",
-      "integrity": "sha512-ZSEpE/EFApR0bJ1w/dUGwTSUvWlpalKqIzkaYdYB7jaftQA/Y2Jav+eT4CMtEYFj+ZK4mswP13Q2acnPBnhGOw=="
-    },
-    "less": {
-      "version": "3.9.0",
-      "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz",
-      "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==",
-      "dev": true,
-      "requires": {
-        "clone": "^2.1.2",
-        "errno": "^0.1.1",
-        "graceful-fs": "^4.1.2",
-        "image-size": "~0.5.0",
-        "mime": "^1.4.1",
-        "mkdirp": "^0.5.0",
-        "promise": "^7.1.1",
-        "request": "^2.83.0",
-        "source-map": "~0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "less-loader": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.1.0.tgz",
-      "integrity": "sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==",
-      "dev": true,
-      "requires": {
-        "clone": "^2.1.1",
-        "loader-utils": "^1.1.0",
-        "pify": "^3.0.0"
-      }
-    },
-    "license-webpack-plugin": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.0.tgz",
-      "integrity": "sha512-vDiBeMWxjE9n6TabQ9J4FH8urFdsRK0Nvxn1cit9biCiR9aq1zBR0X2BlAkEiIG6qPamLeU0GzvIgLkrFc398A==",
-      "dev": true,
-      "requires": {
-        "@types/webpack-sources": "^0.1.5",
-        "webpack-sources": "^1.2.0"
-      }
-    },
-    "lie": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
-      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
-      "dev": true,
-      "requires": {
-        "immediate": "~3.0.5"
-      }
-    },
-    "load-json-file": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
-      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "parse-json": "^2.2.0",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0",
-        "strip-bom": "^2.0.0"
-      },
-      "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        }
-      }
-    },
-    "loader-runner": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
-      "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==",
-      "dev": true
-    },
-    "loader-utils": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
-      "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
-      "dev": true,
-      "requires": {
-        "big.js": "^5.2.2",
-        "emojis-list": "^2.0.0",
-        "json5": "^1.0.1"
-      }
-    },
-    "locate-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-      "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
-      "dev": true,
-      "requires": {
-        "p-locate": "^2.0.0",
-        "path-exists": "^3.0.0"
-      }
-    },
-    "lodash": {
-      "version": "4.17.20",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
-      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
-      "dev": true
-    },
-    "lodash.assign": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
-      "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
-      "dev": true,
-      "optional": true
-    },
-    "lodash.clonedeep": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
-      "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
-      "dev": true
-    },
-    "lodash.debounce": {
-      "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
-      "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
-      "dev": true
-    },
-    "lodash.mergewith": {
-      "version": "4.6.2",
-      "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
-      "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
-      "dev": true,
-      "optional": true
-    },
-    "lodash.tail": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz",
-      "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=",
-      "dev": true
-    },
-    "log4js": {
-      "version": "4.5.1",
-      "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz",
-      "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==",
-      "dev": true,
-      "requires": {
-        "date-format": "^2.0.0",
-        "debug": "^4.1.1",
-        "flatted": "^2.0.0",
-        "rfdc": "^1.1.4",
-        "streamroller": "^1.0.6"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "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": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.0.tgz",
-      "integrity": "sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ==",
-      "dev": true
-    },
-    "loose-envify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
-      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
-      "dev": true,
-      "requires": {
-        "js-tokens": "^3.0.0 || ^4.0.0"
-      }
-    },
-    "loud-rejection": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
-      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "currently-unhandled": "^0.4.1",
-        "signal-exit": "^3.0.0"
-      }
-    },
-    "lru-cache": {
-      "version": "4.1.5",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
-      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
-      "dev": true,
-      "requires": {
-        "pseudomap": "^1.0.2",
-        "yallist": "^2.1.2"
-      }
-    },
-    "magic-string": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
-      "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
-      "dev": true,
-      "requires": {
-        "sourcemap-codec": "^1.4.4"
-      }
-    },
-    "make-dir": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
-      "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
-      "dev": true,
-      "requires": {
-        "pify": "^3.0.0"
-      }
-    },
-    "make-error": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
-      "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
-      "dev": true
-    },
-    "make-fetch-happen": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.2.tgz",
-      "integrity": "sha512-YMJrAjHSb/BordlsDEcVcPyTbiJKkzqMf48N8dAJZT9Zjctrkb6Yg4TY9Sq2AwSIQJFn5qBBKVTYt3vP5FMIHA==",
-      "dev": true,
-      "requires": {
-        "agentkeepalive": "^3.4.1",
-        "cacache": "^11.3.3",
-        "http-cache-semantics": "^3.8.1",
-        "http-proxy-agent": "^2.1.0",
-        "https-proxy-agent": "^2.2.1",
-        "lru-cache": "^5.1.1",
-        "mississippi": "^3.0.0",
-        "node-fetch-npm": "^2.0.2",
-        "promise-retry": "^1.1.1",
-        "socks-proxy-agent": "^4.0.0",
-        "ssri": "^6.0.0"
-      },
-      "dependencies": {
-        "cacache": {
-          "version": "11.3.3",
-          "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz",
-          "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==",
-          "dev": true,
-          "requires": {
-            "bluebird": "^3.5.5",
-            "chownr": "^1.1.1",
-            "figgy-pudding": "^3.5.1",
-            "glob": "^7.1.4",
-            "graceful-fs": "^4.1.15",
-            "lru-cache": "^5.1.1",
-            "mississippi": "^3.0.0",
-            "mkdirp": "^0.5.1",
-            "move-concurrently": "^1.0.1",
-            "promise-inflight": "^1.0.1",
-            "rimraf": "^2.6.3",
-            "ssri": "^6.0.1",
-            "unique-filename": "^1.1.1",
-            "y18n": "^4.0.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "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"
-          }
-        },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "mississippi": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
-          "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
-          "dev": true,
-          "requires": {
-            "concat-stream": "^1.5.0",
-            "duplexify": "^3.4.2",
-            "end-of-stream": "^1.1.0",
-            "flush-write-stream": "^1.0.0",
-            "from2": "^2.1.0",
-            "parallel-transform": "^1.1.0",
-            "pump": "^3.0.0",
-            "pumpify": "^1.3.3",
-            "stream-each": "^1.1.0",
-            "through2": "^2.0.0"
-          }
-        },
-        "pump": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-          "dev": true,
-          "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
-          }
-        },
-        "ssri": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
-          "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
-          "dev": true,
-          "requires": {
-            "figgy-pudding": "^3.5.1"
-          }
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
-        }
-      }
-    },
-    "map-age-cleaner": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
-      "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
-      "dev": true,
-      "requires": {
-        "p-defer": "^1.0.0"
-      }
-    },
-    "map-cache": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
-      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
-      "dev": true
-    },
-    "map-obj": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
-      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
-      "dev": true
-    },
-    "map-visit": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
-      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
-      "dev": true,
-      "requires": {
-        "object-visit": "^1.0.0"
-      }
-    },
-    "marked": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
-      "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg=="
-    },
-    "md5.js": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
-      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
-      "dev": true,
-      "requires": {
-        "hash-base": "^3.0.0",
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.1.2"
-      }
-    },
-    "media-typer": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
-      "dev": true
-    },
-    "mem": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
-      "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
-      "dev": true,
-      "requires": {
-        "map-age-cleaner": "^0.1.1",
-        "mimic-fn": "^2.0.0",
-        "p-is-promise": "^2.0.0"
-      }
-    },
-    "memory-fs": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
-      "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
-      "dev": true,
-      "requires": {
-        "errno": "^0.1.3",
-        "readable-stream": "^2.0.1"
-      }
-    },
-    "meow": {
-      "version": "3.7.0",
-      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
-      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "camelcase-keys": "^2.0.0",
-        "decamelize": "^1.1.2",
-        "loud-rejection": "^1.0.0",
-        "map-obj": "^1.0.1",
-        "minimist": "^1.1.3",
-        "normalize-package-data": "^2.3.4",
-        "object-assign": "^4.0.1",
-        "read-pkg-up": "^1.0.1",
-        "redent": "^1.0.0",
-        "trim-newlines": "^1.0.0"
-      }
-    },
-    "merge-descriptors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
-      "dev": true
-    },
-    "methods": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
-      "dev": true
-    },
-    "micromatch": {
-      "version": "3.1.10",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-      "dev": true,
-      "requires": {
-        "arr-diff": "^4.0.0",
-        "array-unique": "^0.3.2",
-        "braces": "^2.3.1",
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "extglob": "^2.0.4",
-        "fragment-cache": "^0.2.1",
-        "kind-of": "^6.0.2",
-        "nanomatch": "^1.2.9",
-        "object.pick": "^1.3.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.2"
-      }
-    },
-    "miller-rabin": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
-      "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.0.0",
-        "brorand": "^1.0.1"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "mime": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-      "dev": true
-    },
-    "mime-db": {
-      "version": "1.44.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
-      "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
-      "dev": true
-    },
-    "mime-types": {
-      "version": "2.1.27",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
-      "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
-      "dev": true,
-      "requires": {
-        "mime-db": "1.44.0"
-      }
-    },
-    "mimic-fn": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
-      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
-      "dev": true
-    },
-    "mini-css-extract-plugin": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz",
-      "integrity": "sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.1.0",
-        "schema-utils": "^1.0.0",
-        "webpack-sources": "^1.1.0"
-      }
-    },
-    "minimalistic-assert": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
-      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
-      "dev": true
-    },
-    "minimalistic-crypto-utils": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
-      "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
-      "dev": true
-    },
-    "minimatch": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
-      "requires": {
-        "brace-expansion": "^1.1.7"
-      }
-    },
-    "minimist": {
-      "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",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-      "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "^5.1.2",
-        "yallist": "^3.0.0"
-      },
-      "dependencies": {
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
-        }
-      }
-    },
-    "minizlib": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
-      "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
-      "dev": true,
-      "requires": {
-        "minipass": "^2.9.0"
-      }
-    },
-    "mississippi": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz",
-      "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==",
-      "dev": true,
-      "requires": {
-        "concat-stream": "^1.5.0",
-        "duplexify": "^3.4.2",
-        "end-of-stream": "^1.1.0",
-        "flush-write-stream": "^1.0.0",
-        "from2": "^2.1.0",
-        "parallel-transform": "^1.1.0",
-        "pump": "^2.0.1",
-        "pumpify": "^1.3.3",
-        "stream-each": "^1.1.0",
-        "through2": "^2.0.0"
-      }
-    },
-    "mixin-deep": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
-      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
-      "dev": true,
-      "requires": {
-        "for-in": "^1.0.2",
-        "is-extendable": "^1.0.1"
-      },
-      "dependencies": {
-        "is-extendable": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
-          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
-          "dev": true,
-          "requires": {
-            "is-plain-object": "^2.0.4"
-          }
-        }
-      }
-    },
-    "mixin-object": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz",
-      "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=",
-      "dev": true,
-      "requires": {
-        "for-in": "^0.1.3",
-        "is-extendable": "^0.1.1"
-      },
-      "dependencies": {
-        "for-in": {
-          "version": "0.1.8",
-          "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz",
-          "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=",
-          "dev": true
-        }
-      }
-    },
-    "mkdirp": {
-      "version": "0.5.5",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
-      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
-      "dev": true,
-      "requires": {
-        "minimist": "^1.2.5"
-      }
-    },
-    "moment": {
-      "version": "2.24.0",
-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
-      "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
-    },
-    "move-concurrently": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
-      "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
-      "dev": true,
-      "requires": {
-        "aproba": "^1.1.1",
-        "copy-concurrently": "^1.0.0",
-        "fs-write-stream-atomic": "^1.0.8",
-        "mkdirp": "^0.5.1",
-        "rimraf": "^2.5.4",
-        "run-queue": "^1.0.3"
-      }
-    },
-    "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-      "dev": true
-    },
-    "multicast-dns": {
-      "version": "6.2.3",
-      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
-      "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
-      "dev": true,
-      "requires": {
-        "dns-packet": "^1.3.1",
-        "thunky": "^1.0.2"
-      }
-    },
-    "multicast-dns-service-types": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
-      "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
-      "dev": true
-    },
-    "mute-stream": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
-      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
-      "dev": true
-    },
-    "nan": {
-      "version": "2.14.2",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
-      "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
-      "dev": true,
-      "optional": true
-    },
-    "nanomatch": {
-      "version": "1.2.13",
-      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
-      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
-      "dev": true,
-      "requires": {
-        "arr-diff": "^4.0.0",
-        "array-unique": "^0.3.2",
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "fragment-cache": "^0.2.1",
-        "is-windows": "^1.0.2",
-        "kind-of": "^6.0.2",
-        "object.pick": "^1.3.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      }
-    },
-    "negotiator": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
-      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
-      "dev": true
-    },
-    "neo-async": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
-      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
-      "dev": true
-    },
-    "ng-mocks": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-7.6.0.tgz",
-      "integrity": "sha512-Zorpd5I6KmvTtiYwcjymzCaortznMZr5CRB737XaNheITTUb2rVLUoEBk1dwQE3b/Cp5sByuS85fzwJRvjEXKQ=="
-    },
-    "ngx-markdown": {
-      "version": "8.2.1",
-      "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-8.2.1.tgz",
-      "integrity": "sha512-59LG8rEoOwDsZyyJckp+QDnW/c5wMaRpNkb6TWktlBVTfQKyAYHr6BuSskVbZ4y8nsj54UQg0CDFLBOfUiqOwA==",
-      "requires": {
-        "@types/marked": "^0.6.5",
-        "katex": "^0.11.1",
-        "marked": "^0.7.0",
-        "prismjs": "^1.16.0",
-        "tslib": "^1.9.0"
-      }
-    },
-    "ngx-moment": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/ngx-moment/-/ngx-moment-3.3.0.tgz",
-      "integrity": "sha512-6fpllpJqLfjRWboOhphgeEYt+rzIA9O29rG5QWCebRt2X0uNk4P93sLEb0S8lbDF0dEp2NOC3UOD+xoCVlJQhA==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "ngx-speculoos": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/ngx-speculoos/-/ngx-speculoos-1.1.0.tgz",
-      "integrity": "sha512-gtQ6t3KOgu6TCscnOOFl4PmV35R36vgafhofJwqIcIrWBCcPFwKYTAyf5TUwkrW7GEayxEqUREGO6g4rBfvNRw==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "nice-try": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
-      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
-      "dev": true
-    },
-    "node-fetch-npm": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz",
-      "integrity": "sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg==",
-      "dev": true,
-      "requires": {
-        "encoding": "^0.1.11",
-        "json-parse-better-errors": "^1.0.0",
-        "safe-buffer": "^5.1.1"
-      }
-    },
-    "node-forge": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
-      "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
-      "dev": true
-    },
-    "node-gyp": {
-      "version": "3.8.0",
-      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
-      "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "fstream": "^1.0.0",
-        "glob": "^7.0.3",
-        "graceful-fs": "^4.1.2",
-        "mkdirp": "^0.5.0",
-        "nopt": "2 || 3",
-        "npmlog": "0 || 1 || 2 || 3 || 4",
-        "osenv": "0",
-        "request": "^2.87.0",
-        "rimraf": "2",
-        "semver": "~5.3.0",
-        "tar": "^2.0.0",
-        "which": "1"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
-          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "node-libs-browser": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
-      "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
-      "dev": true,
-      "requires": {
-        "assert": "^1.1.1",
-        "browserify-zlib": "^0.2.0",
-        "buffer": "^4.3.0",
-        "console-browserify": "^1.1.0",
-        "constants-browserify": "^1.0.0",
-        "crypto-browserify": "^3.11.0",
-        "domain-browser": "^1.1.1",
-        "events": "^3.0.0",
-        "https-browserify": "^1.0.0",
-        "os-browserify": "^0.3.0",
-        "path-browserify": "0.0.1",
-        "process": "^0.11.10",
-        "punycode": "^1.2.4",
-        "querystring-es3": "^0.2.0",
-        "readable-stream": "^2.3.3",
-        "stream-browserify": "^2.0.1",
-        "stream-http": "^2.7.2",
-        "string_decoder": "^1.0.0",
-        "timers-browserify": "^2.0.4",
-        "tty-browserify": "0.0.0",
-        "url": "^0.11.0",
-        "util": "^0.11.0",
-        "vm-browserify": "^1.0.1"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
-          "dev": true
-        }
-      }
-    },
-    "node-releases": {
-      "version": "1.1.67",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz",
-      "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==",
-      "dev": true
-    },
-    "node-sass": {
-      "version": "4.11.0",
-      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz",
-      "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "async-foreach": "^0.1.3",
-        "chalk": "^1.1.1",
-        "cross-spawn": "^3.0.0",
-        "gaze": "^1.0.0",
-        "get-stdin": "^4.0.1",
-        "glob": "^7.0.3",
-        "in-publish": "^2.0.0",
-        "lodash.assign": "^4.2.0",
-        "lodash.clonedeep": "^4.3.2",
-        "lodash.mergewith": "^4.6.0",
-        "meow": "^3.7.0",
-        "mkdirp": "^0.5.1",
-        "nan": "^2.10.0",
-        "node-gyp": "^3.8.0",
-        "npmlog": "^4.0.0",
-        "request": "^2.88.0",
-        "sass-graph": "^2.2.4",
-        "stdout-stream": "^1.4.0",
-        "true-case-path": "^1.0.2"
-      },
-      "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,
-          "optional": true
-        },
-        "chalk": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
-          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
-          "dev": true,
-          "optional": 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"
-          }
-        },
-        "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,
-          "optional": true
-        }
-      }
-    },
-    "nopt": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
-      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "abbrev": "1"
-      }
-    },
-    "normalize-package-data": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
-      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
-      "dev": true,
-      "requires": {
-        "hosted-git-info": "^2.1.4",
-        "resolve": "^1.10.0",
-        "semver": "2 || 3 || 4 || 5",
-        "validate-npm-package-license": "^3.0.1"
-      }
-    },
-    "normalize-path": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
-      "dev": true,
-      "requires": {
-        "remove-trailing-separator": "^1.0.1"
-      }
-    },
-    "normalize-range": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
-      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
-      "dev": true
-    },
-    "npm-bundled": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
-      "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
-      "dev": true,
-      "requires": {
-        "npm-normalize-package-bin": "^1.0.1"
-      }
-    },
-    "npm-normalize-package-bin": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
-      "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
-      "dev": true
-    },
-    "npm-package-arg": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz",
-      "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==",
-      "dev": true,
-      "requires": {
-        "hosted-git-info": "^2.6.0",
-        "osenv": "^0.1.5",
-        "semver": "^5.5.0",
-        "validate-npm-package-name": "^3.0.0"
-      }
-    },
-    "npm-packlist": {
-      "version": "1.4.8",
-      "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
-      "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
-      "dev": true,
-      "requires": {
-        "ignore-walk": "^3.0.1",
-        "npm-bundled": "^1.0.1",
-        "npm-normalize-package-bin": "^1.0.1"
-      }
-    },
-    "npm-pick-manifest": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz",
-      "integrity": "sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==",
-      "dev": true,
-      "requires": {
-        "figgy-pudding": "^3.5.1",
-        "npm-package-arg": "^6.0.0",
-        "semver": "^5.4.1"
-      }
-    },
-    "npm-registry-fetch": {
-      "version": "3.9.1",
-      "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.1.tgz",
-      "integrity": "sha512-VQCEZlydXw4AwLROAXWUR7QDfe2Y8Id/vpAgp6TI1/H78a4SiQ1kQrKZALm5/zxM5n4HIi+aYb+idUAV/RuY0Q==",
-      "dev": true,
-      "requires": {
-        "JSONStream": "^1.3.4",
-        "bluebird": "^3.5.1",
-        "figgy-pudding": "^3.4.1",
-        "lru-cache": "^5.1.1",
-        "make-fetch-happen": "^4.0.2",
-        "npm-package-arg": "^6.1.0"
-      },
-      "dependencies": {
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
-        }
-      }
-    },
-    "npm-run-path": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
-      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
-      "dev": true,
-      "requires": {
-        "path-key": "^2.0.0"
-      }
-    },
-    "npmlog": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
-      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
-      "dev": true,
-      "requires": {
-        "are-we-there-yet": "~1.1.2",
-        "console-control-strings": "~1.1.0",
-        "gauge": "~2.7.3",
-        "set-blocking": "~2.0.0"
-      }
-    },
-    "num2fraction": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
-      "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
-      "dev": true
-    },
-    "number-is-nan": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
-      "dev": true
-    },
-    "oauth-sign": {
-      "version": "0.9.0",
-      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
-      "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=",
-      "dev": true
-    },
-    "object-component": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
-      "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
-      "dev": true
-    },
-    "object-copy": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
-      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
-      "dev": true,
-      "requires": {
-        "copy-descriptor": "^0.1.0",
-        "define-property": "^0.2.5",
-        "kind-of": "^3.0.3"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "object-inspect": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
-      "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
-      "dev": true
-    },
-    "object-is": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz",
-      "integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.18.0-next.1"
-      }
-    },
-    "object-keys": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-      "dev": true
-    },
-    "object-visit": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
-      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.0"
-      }
-    },
-    "object.assign": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
-      "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.0",
-        "define-properties": "^1.1.3",
-        "has-symbols": "^1.0.1",
-        "object-keys": "^1.1.1"
-      }
-    },
-    "object.pick": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
-      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.1"
-      }
-    },
-    "obuf": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
-      "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
-      "dev": true
-    },
-    "on-finished": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
-      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
-      "dev": true,
-      "requires": {
-        "ee-first": "1.1.1"
-      }
-    },
-    "on-headers": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
-      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
-      "dev": true
-    },
-    "once": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "dev": true,
-      "requires": {
-        "wrappy": "1"
-      }
-    },
-    "onetime": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
-      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
-      "dev": true,
-      "requires": {
-        "mimic-fn": "^1.0.0"
-      },
-      "dependencies": {
-        "mimic-fn": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
-          "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
-          "dev": true
-        }
-      }
-    },
-    "opn": {
-      "version": "5.4.0",
-      "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz",
-      "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==",
-      "dev": true,
-      "requires": {
-        "is-wsl": "^1.1.0"
-      }
-    },
-    "optimist": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
-      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-      "dev": true,
-      "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": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
-      "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
-      "dev": true,
-      "requires": {
-        "url-parse": "^1.4.3"
-      }
-    },
-    "os-browserify": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
-      "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
-      "dev": true
-    },
-    "os-homedir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
-      "dev": true
-    },
-    "os-locale": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
-      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "lcid": "^1.0.0"
-      }
-    },
-    "os-tmpdir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
-      "dev": true
-    },
-    "osenv": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-      "dev": true,
-      "requires": {
-        "os-homedir": "^1.0.0",
-        "os-tmpdir": "^1.0.0"
-      }
-    },
-    "p-defer": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
-      "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
-      "dev": true
-    },
-    "p-finally": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
-      "dev": true
-    },
-    "p-is-promise": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
-      "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
-      "dev": true
-    },
-    "p-limit": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
-      "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
-      "dev": true,
-      "requires": {
-        "p-try": "^1.0.0"
-      }
-    },
-    "p-locate": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
-      "dev": true,
-      "requires": {
-        "p-limit": "^1.1.0"
-      }
-    },
-    "p-map": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
-      "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==",
-      "dev": true
-    },
-    "p-try": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
-      "dev": true
-    },
-    "pacote": {
-      "version": "9.4.0",
-      "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.0.tgz",
-      "integrity": "sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w==",
-      "dev": true,
-      "requires": {
-        "bluebird": "^3.5.3",
-        "cacache": "^11.3.2",
-        "figgy-pudding": "^3.5.1",
-        "get-stream": "^4.1.0",
-        "glob": "^7.1.3",
-        "lru-cache": "^5.1.1",
-        "make-fetch-happen": "^4.0.1",
-        "minimatch": "^3.0.4",
-        "minipass": "^2.3.5",
-        "mississippi": "^3.0.0",
-        "mkdirp": "^0.5.1",
-        "normalize-package-data": "^2.4.0",
-        "npm-package-arg": "^6.1.0",
-        "npm-packlist": "^1.1.12",
-        "npm-pick-manifest": "^2.2.3",
-        "npm-registry-fetch": "^3.8.0",
-        "osenv": "^0.1.5",
-        "promise-inflight": "^1.0.1",
-        "promise-retry": "^1.1.1",
-        "protoduck": "^5.0.1",
-        "rimraf": "^2.6.2",
-        "safe-buffer": "^5.1.2",
-        "semver": "^5.6.0",
-        "ssri": "^6.0.1",
-        "tar": "^4.4.8",
-        "unique-filename": "^1.1.1",
-        "which": "^1.3.1"
-      },
-      "dependencies": {
-        "cacache": {
-          "version": "11.3.3",
-          "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz",
-          "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==",
-          "dev": true,
-          "requires": {
-            "bluebird": "^3.5.5",
-            "chownr": "^1.1.1",
-            "figgy-pudding": "^3.5.1",
-            "glob": "^7.1.4",
-            "graceful-fs": "^4.1.15",
-            "lru-cache": "^5.1.1",
-            "mississippi": "^3.0.0",
-            "mkdirp": "^0.5.1",
-            "move-concurrently": "^1.0.1",
-            "promise-inflight": "^1.0.1",
-            "rimraf": "^2.6.3",
-            "ssri": "^6.0.1",
-            "unique-filename": "^1.1.1",
-            "y18n": "^4.0.0"
-          },
-          "dependencies": {
-            "glob": {
-              "version": "7.1.6",
-              "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-              "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-              "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"
-              }
-            }
-          }
-        },
-        "get-stream": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
-          "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
-          "dev": true,
-          "requires": {
-            "pump": "^3.0.0"
-          }
-        },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "mississippi": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
-          "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
-          "dev": true,
-          "requires": {
-            "concat-stream": "^1.5.0",
-            "duplexify": "^3.4.2",
-            "end-of-stream": "^1.1.0",
-            "flush-write-stream": "^1.0.0",
-            "from2": "^2.1.0",
-            "parallel-transform": "^1.1.0",
-            "pump": "^3.0.0",
-            "pumpify": "^1.3.3",
-            "stream-each": "^1.1.0",
-            "through2": "^2.0.0"
-          }
-        },
-        "pump": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-          "dev": true,
-          "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
-          }
-        },
-        "ssri": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
-          "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
-          "dev": true,
-          "requires": {
-            "figgy-pudding": "^3.5.1"
-          }
-        },
-        "tar": {
-          "version": "4.4.13",
-          "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
-          "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
-          "dev": true,
-          "requires": {
-            "chownr": "^1.1.1",
-            "fs-minipass": "^1.2.5",
-            "minipass": "^2.8.6",
-            "minizlib": "^1.2.1",
-            "mkdirp": "^0.5.0",
-            "safe-buffer": "^5.1.2",
-            "yallist": "^3.0.3"
-          }
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
-        }
-      }
-    },
-    "pako": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
-      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
-      "dev": true
-    },
-    "parallel-transform": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
-      "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
-      "dev": true,
-      "requires": {
-        "cyclist": "^1.0.1",
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.1.5"
-      }
-    },
-    "parse-asn1": {
-      "version": "5.1.6",
-      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
-      "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
-      "dev": true,
-      "requires": {
-        "asn1.js": "^5.2.0",
-        "browserify-aes": "^1.0.0",
-        "evp_bytestokey": "^1.0.0",
-        "pbkdf2": "^3.0.3",
-        "safe-buffer": "^5.1.1"
-      }
-    },
-    "parse-json": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
-      "dev": true,
-      "requires": {
-        "error-ex": "^1.2.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
-    },
-    "parseqs": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
-      "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
-      "dev": true,
-      "requires": {
-        "better-assert": "~1.0.0"
-      }
-    },
-    "parseuri": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
-      "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
-      "dev": true,
-      "requires": {
-        "better-assert": "~1.0.0"
-      }
-    },
-    "parseurl": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
-      "dev": true
-    },
-    "pascalcase": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
-      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
-      "dev": true
-    },
-    "path-browserify": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
-      "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
-      "dev": true
-    },
-    "path-dirname": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
-      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
-      "dev": true
-    },
-    "path-exists": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-      "dev": true
-    },
-    "path-is-absolute": {
-      "version": "1.0.1",
-      "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "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=",
-      "dev": true
-    },
-    "path-key": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
-      "dev": true
-    },
-    "path-parse": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
-      "dev": true
-    },
-    "path-to-regexp": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
-      "dev": true
-    },
-    "path-type": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
-      "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
-      "dev": true,
-      "requires": {
-        "pify": "^3.0.0"
-      }
-    },
-    "pbkdf2": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
-      "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
-      "dev": true,
-      "requires": {
-        "create-hash": "^1.1.2",
-        "create-hmac": "^1.1.4",
-        "ripemd160": "^2.0.1",
-        "safe-buffer": "^5.0.1",
-        "sha.js": "^2.4.8"
-      }
-    },
-    "performance-now": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
-      "dev": true
-    },
-    "picomatch": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
-      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
-      "dev": true
-    },
-    "pify": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
-      "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
-      "dev": true
-    },
-    "pinkie": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "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"
-      }
-    },
-    "pkg-dir": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
-      "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
-      "dev": true,
-      "requires": {
-        "find-up": "^2.1.0"
-      }
-    },
-    "popper.js": {
-      "version": "1.14.6",
-      "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.6.tgz",
-      "integrity": "sha512-AGwHGQBKumlk/MDfrSOf0JHhJCImdDMcGNoqKmKkU+68GFazv3CQ6q9r7Ja1sKDZmYWTckY/uLyEznheTDycnA=="
-    },
-    "portfinder": {
-      "version": "1.0.28",
-      "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
-      "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
-      "dev": true,
-      "requires": {
-        "async": "^2.6.2",
-        "debug": "^3.1.1",
-        "mkdirp": "^0.5.5"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.7",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-          "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
-        }
-      }
-    },
-    "posix-character-classes": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
-      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
-      "dev": true
-    },
-    "postcss": {
-      "version": "7.0.14",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz",
-      "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==",
-      "dev": true,
-      "requires": {
-        "chalk": "^2.4.2",
-        "source-map": "^0.6.1",
-        "supports-color": "^6.1.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-import": {
-      "version": "12.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz",
-      "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.1",
-        "postcss-value-parser": "^3.2.3",
-        "read-cache": "^1.0.0",
-        "resolve": "^1.1.7"
-      }
-    },
-    "postcss-load-config": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz",
-      "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==",
-      "dev": true,
-      "requires": {
-        "cosmiconfig": "^5.0.0",
-        "import-cwd": "^2.0.0"
-      }
-    },
-    "postcss-loader": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
-      "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.1.0",
-        "postcss": "^7.0.0",
-        "postcss-load-config": "^2.0.0",
-        "schema-utils": "^1.0.0"
-      }
-    },
-    "postcss-value-parser": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-      "dev": true
-    },
-    "prismjs": {
-      "version": "1.20.0",
-      "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.20.0.tgz",
-      "integrity": "sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ==",
-      "requires": {
-        "clipboard": "^2.0.0"
-      }
-    },
-    "process": {
-      "version": "0.11.10",
-      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
-      "dev": true
-    },
-    "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==",
-      "dev": true
-    },
-    "promise": {
-      "version": "7.3.1",
-      "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
-      "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "asap": "~2.0.3"
-      }
-    },
-    "promise-inflight": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
-      "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
-      "dev": true
-    },
-    "promise-retry": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz",
-      "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=",
-      "dev": true,
-      "requires": {
-        "err-code": "^1.0.0",
-        "retry": "^0.10.0"
-      }
-    },
-    "protoduck": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz",
-      "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==",
-      "dev": true,
-      "requires": {
-        "genfun": "^5.0.0"
-      }
-    },
-    "protractor": {
-      "version": "5.4.1",
-      "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.1.tgz",
-      "integrity": "sha512-ORey5ewQMYiXQxcQohsqEiKYOg/r5yJoJbt0tuROmmgajdg/CA3gTOZNIFJncUVMAJIk5YFqBBLUjKVmQO6tfA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "^6.0.46",
-        "@types/q": "^0.0.32",
-        "@types/selenium-webdriver": "^3.0.0",
-        "blocking-proxy": "^1.0.0",
-        "browserstack": "^1.5.1",
-        "chalk": "^1.1.3",
-        "glob": "^7.0.3",
-        "jasmine": "2.8.0",
-        "jasminewd2": "^2.1.0",
-        "optimist": "~0.6.0",
-        "q": "1.4.1",
-        "saucelabs": "^1.5.0",
-        "selenium-webdriver": "3.6.0",
-        "source-map-support": "~0.4.0",
-        "webdriver-js-extender": "2.1.0",
-        "webdriver-manager": "^12.0.6"
-      },
-      "dependencies": {
-        "@types/node": {
-          "version": "6.14.13",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.13.tgz",
-          "integrity": "sha512-J1F0XJ/9zxlZel5ZlbeSuHW2OpabrUAqpFuC2sm2I3by8sERQ8+KCjNKUcq8QHuzpGMWiJpo9ZxeHrqrP2KzQw==",
-          "dev": true
-        },
-        "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"
-          }
-        },
-        "del": {
-          "version": "2.2.2",
-          "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
-          "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
-          "dev": true,
-          "requires": {
-            "globby": "^5.0.0",
-            "is-path-cwd": "^1.0.0",
-            "is-path-in-cwd": "^1.0.0",
-            "object-assign": "^4.0.1",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0",
-            "rimraf": "^2.2.8"
-          }
-        },
-        "globby": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
-          "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
-          "dev": true,
-          "requires": {
-            "array-union": "^1.0.1",
-            "arrify": "^1.0.0",
-            "glob": "^7.0.3",
-            "object-assign": "^4.0.1",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          }
-        },
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "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
-        },
-        "source-map-support": {
-          "version": "0.4.18",
-          "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
-          "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
-          "dev": true,
-          "requires": {
-            "source-map": "^0.5.6"
-          }
-        },
-        "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
-        },
-        "webdriver-manager": {
-          "version": "12.1.7",
-          "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.7.tgz",
-          "integrity": "sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA==",
-          "dev": true,
-          "requires": {
-            "adm-zip": "^0.4.9",
-            "chalk": "^1.1.1",
-            "del": "^2.2.0",
-            "glob": "^7.0.3",
-            "ini": "^1.3.4",
-            "minimist": "^1.2.0",
-            "q": "^1.4.1",
-            "request": "^2.87.0",
-            "rimraf": "^2.5.2",
-            "semver": "^5.3.0",
-            "xml2js": "^0.4.17"
-          }
-        }
-      }
-    },
-    "proxy-addr": {
-      "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.1"
-      }
-    },
-    "prr": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
-      "dev": true
-    },
-    "pseudomap": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
-      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
-      "dev": true
-    },
-    "psl": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
-      "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
-      "dev": true
-    },
-    "public-encrypt": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
-      "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.1.0",
-        "browserify-rsa": "^4.0.0",
-        "create-hash": "^1.1.0",
-        "parse-asn1": "^5.0.0",
-        "randombytes": "^2.0.1",
-        "safe-buffer": "^5.1.2"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "pump": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
-      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.1.0",
-        "once": "^1.3.1"
-      }
-    },
-    "pumpify": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
-      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
-      "dev": true,
-      "requires": {
-        "duplexify": "^3.6.0",
-        "inherits": "^2.0.3",
-        "pump": "^2.0.0"
-      }
-    },
-    "punycode": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
-      "dev": true
-    },
-    "q": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz",
-      "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=",
-      "dev": true
-    },
-    "qjobs": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
-      "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
-      "dev": true
-    },
-    "qs": {
-      "version": "6.5.2",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
-      "dev": true
-    },
-    "querystring": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
-      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
-      "dev": true
-    },
-    "querystring-es3": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
-      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
-      "dev": true
-    },
-    "querystringify": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
-      "dev": true
-    },
-    "randombytes": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
-      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "^5.1.0"
-      }
-    },
-    "randomfill": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
-      "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
-      "dev": true,
-      "requires": {
-        "randombytes": "^2.0.5",
-        "safe-buffer": "^5.1.0"
-      }
-    },
-    "range-parser": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
-      "dev": true
-    },
-    "raw-body": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
-      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
-      "dev": true,
-      "requires": {
-        "bytes": "3.1.0",
-        "http-errors": "1.7.2",
-        "iconv-lite": "0.4.24",
-        "unpipe": "1.0.0"
-      },
-      "dependencies": {
-        "bytes": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
-          "dev": true
-        }
-      }
-    },
-    "raw-loader": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-1.0.0.tgz",
-      "integrity": "sha512-Uqy5AqELpytJTRxYT4fhltcKPj0TyaEpzJDcGz7DFJi+pQOOi3GjR/DOdxTkTsF+NzhnldIoG6TORaBlInUuqA==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.1.0",
-        "schema-utils": "^1.0.0"
-      }
-    },
-    "read-cache": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
-      "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=",
-      "dev": true,
-      "requires": {
-        "pify": "^2.3.0"
-      },
-      "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        }
-      }
-    },
-    "read-pkg": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
-      "dev": true,
-      "requires": {
-        "load-json-file": "^1.0.0",
-        "normalize-package-data": "^2.3.2",
-        "path-type": "^1.0.0"
-      },
-      "dependencies": {
-        "path-type": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
-          "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          }
-        },
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        }
-      }
-    },
-    "read-pkg-up": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
-      "dev": true,
-      "requires": {
-        "find-up": "^1.0.0",
-        "read-pkg": "^1.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
-          "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
-          "dev": true,
-          "requires": {
-            "path-exists": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          }
-        },
-        "path-exists": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
-          "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
-          "dev": true,
-          "requires": {
-            "pinkie-promise": "^2.0.0"
-          }
-        }
-      }
-    },
-    "readable-stream": {
-      "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",
-        "isarray": "~1.0.0",
-        "process-nextick-args": "~2.0.0",
-        "safe-buffer": "~5.1.1",
-        "string_decoder": "~1.1.1",
-        "util-deprecate": "~1.0.1"
-      }
-    },
-    "readdirp": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
-      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.11",
-        "micromatch": "^3.1.10",
-        "readable-stream": "^2.0.2"
-      }
-    },
-    "rechoir": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
-      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
-      "dev": true,
-      "requires": {
-        "resolve": "^1.1.6"
-      }
-    },
-    "redent": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "indent-string": "^2.1.0",
-        "strip-indent": "^1.0.1"
-      }
-    },
-    "reflect-metadata": {
-      "version": "0.1.13",
-      "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
-      "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
-      "dev": true
-    },
-    "regenerator-runtime": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
-      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
-      "dev": true
-    },
-    "regex-not": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
-      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^3.0.2",
-        "safe-regex": "^1.1.0"
-      }
-    },
-    "regexp.prototype.flags": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
-      "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.17.0-next.1"
-      },
-      "dependencies": {
-        "es-abstract": {
-          "version": "1.17.7",
-          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
-          "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
-          "dev": true,
-          "requires": {
-            "es-to-primitive": "^1.2.1",
-            "function-bind": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.1",
-            "is-callable": "^1.2.2",
-            "is-regex": "^1.1.1",
-            "object-inspect": "^1.8.0",
-            "object-keys": "^1.1.1",
-            "object.assign": "^4.1.1",
-            "string.prototype.trimend": "^1.0.1",
-            "string.prototype.trimstart": "^1.0.1"
-          }
-        }
-      }
-    },
-    "remove-trailing-separator": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
-      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
-      "dev": true
-    },
-    "repeat-element": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
-      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
-      "dev": true
-    },
-    "repeat-string": {
-      "version": "1.6.1",
-      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
-      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
-      "dev": true
-    },
-    "repeating": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
-      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
-      "dev": true,
-      "requires": {
-        "is-finite": "^1.0.0"
-      }
-    },
-    "request": {
-      "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",
-        "caseless": "~0.12.0",
-        "combined-stream": "~1.0.6",
-        "extend": "~3.0.2",
-        "forever-agent": "~0.6.1",
-        "form-data": "~2.3.2",
-        "har-validator": "~5.1.3",
-        "http-signature": "~1.2.0",
-        "is-typedarray": "~1.0.0",
-        "isstream": "~0.1.2",
-        "json-stringify-safe": "~5.0.1",
-        "mime-types": "~2.1.19",
-        "oauth-sign": "~0.9.0",
-        "performance-now": "^2.1.0",
-        "qs": "~6.5.2",
-        "safe-buffer": "^5.1.2",
-        "tough-cookie": "~2.5.0",
-        "tunnel-agent": "^0.6.0",
-        "uuid": "^3.3.2"
-      }
-    },
-    "require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-      "dev": true
-    },
-    "require-main-filename": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
-      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
-      "dev": true
-    },
-    "requires-port": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
-      "dev": true
-    },
-    "resolve": {
-      "version": "1.19.0",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
-      "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
-      "dev": true,
-      "requires": {
-        "is-core-module": "^2.1.0",
-        "path-parse": "^1.0.6"
-      }
-    },
-    "resolve-cwd": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
-      "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
-      "dev": true,
-      "requires": {
-        "resolve-from": "^3.0.0"
-      }
-    },
-    "resolve-from": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
-      "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
-      "dev": true
-    },
-    "resolve-url": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
-      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
-      "dev": true
-    },
-    "restore-cursor": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
-      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
-      "dev": true,
-      "requires": {
-        "onetime": "^2.0.0",
-        "signal-exit": "^3.0.2"
-      }
-    },
-    "ret": {
-      "version": "0.1.15",
-      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
-      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
-      "dev": true
-    },
-    "retry": {
-      "version": "0.10.1",
-      "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
-      "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
-      "dev": true
-    },
-    "rfdc": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz",
-      "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==",
-      "dev": true
-    },
-    "rimraf": {
-      "version": "2.6.3",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
-      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.1.3"
-      }
-    },
-    "ripemd160": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
-      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
-      "dev": true,
-      "requires": {
-        "hash-base": "^3.0.0",
-        "inherits": "^2.0.1"
-      }
-    },
-    "run-async": {
-      "version": "2.4.1",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
-      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
-      "dev": true
-    },
-    "run-queue": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
-      "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
-      "dev": true,
-      "requires": {
-        "aproba": "^1.1.1"
-      }
-    },
-    "rxjs": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
-      "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "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==",
-      "dev": true
-    },
-    "safe-regex": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
-      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
-      "dev": true,
-      "requires": {
-        "ret": "~0.1.10"
-      }
-    },
-    "safer-buffer": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true
-    },
-    "sass-graph": {
-      "version": "2.2.6",
-      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.6.tgz",
-      "integrity": "sha512-MKuEYXFSGuRSi8FZ3A7imN1CeVn9Gpw0/SFJKdL1ejXJneI9a5rwlEZrKejhEFAA3O6yr3eIyl/WuvASvlT36g==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "glob": "^7.0.0",
-        "lodash": "^4.0.0",
-        "scss-tokenizer": "^0.2.3",
-        "yargs": "^7.0.0"
-      }
-    },
-    "sass-loader": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz",
-      "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==",
-      "dev": true,
-      "requires": {
-        "clone-deep": "^2.0.1",
-        "loader-utils": "^1.0.1",
-        "lodash.tail": "^4.1.1",
-        "neo-async": "^2.5.0",
-        "pify": "^3.0.0",
-        "semver": "^5.5.0"
-      }
-    },
-    "saucelabs": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz",
-      "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==",
-      "dev": true,
-      "requires": {
-        "https-proxy-agent": "^2.2.1"
-      }
-    },
-    "sax": {
-      "version": "0.5.8",
-      "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
-      "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=",
-      "dev": true
-    },
-    "schema-utils": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
-      "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
-      "dev": true,
-      "requires": {
-        "ajv": "^6.1.0",
-        "ajv-errors": "^1.0.0",
-        "ajv-keywords": "^3.1.0"
-      }
-    },
-    "scss-tokenizer": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
-      "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "js-base64": "^2.1.8",
-        "source-map": "^0.4.2"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.4.4",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
-          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "amdefine": ">=0.0.4"
-          }
-        }
-      }
-    },
-    "select": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
-      "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
-      "optional": true
-    },
-    "select-hose": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
-      "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
-      "dev": true
-    },
-    "selenium-webdriver": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz",
-      "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==",
-      "dev": true,
-      "requires": {
-        "jszip": "^3.1.3",
-        "rimraf": "^2.5.4",
-        "tmp": "0.0.30",
-        "xml2js": "^0.4.17"
-      },
-      "dependencies": {
-        "tmp": {
-          "version": "0.0.30",
-          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
-          "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
-          "dev": true,
-          "requires": {
-            "os-tmpdir": "~1.0.1"
-          }
-        }
-      }
-    },
-    "selfsigned": {
-      "version": "1.10.8",
-      "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
-      "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
-      "dev": true,
-      "requires": {
-        "node-forge": "^0.10.0"
-      }
-    },
-    "semver": {
-      "version": "5.6.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
-      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
-      "dev": true
-    },
-    "semver-dsl": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
-      "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=",
-      "dev": true,
-      "requires": {
-        "semver": "^5.3.0"
-      }
-    },
-    "semver-intersect": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz",
-      "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==",
-      "dev": true,
-      "requires": {
-        "semver": "^5.0.0"
-      }
-    },
-    "send": {
-      "version": "0.17.1",
-      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
-      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
-      "dev": true,
-      "requires": {
-        "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "destroy": "~1.0.4",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "etag": "~1.8.1",
-        "fresh": "0.5.2",
-        "http-errors": "~1.7.2",
-        "mime": "1.6.0",
-        "ms": "2.1.1",
-        "on-finished": "~2.3.0",
-        "range-parser": "~1.2.1",
-        "statuses": "~1.5.0"
-      },
-      "dependencies": {
-        "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
-          "dev": true
-        }
-      }
-    },
-    "serialize-javascript": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
-      "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
-      "dev": true
-    },
-    "serve-index": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
-      "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
-      "dev": true,
-      "requires": {
-        "accepts": "~1.3.4",
-        "batch": "0.6.1",
-        "debug": "2.6.9",
-        "escape-html": "~1.0.3",
-        "http-errors": "~1.6.2",
-        "mime-types": "~2.1.17",
-        "parseurl": "~1.3.2"
-      },
-      "dependencies": {
-        "http-errors": {
-          "version": "1.6.3",
-          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
-          "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
-          "dev": true,
-          "requires": {
-            "depd": "~1.1.2",
-            "inherits": "2.0.3",
-            "setprototypeof": "1.1.0",
-            "statuses": ">= 1.4.0 < 2"
-          }
-        },
-        "setprototypeof": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
-          "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
-          "dev": true
-        }
-      }
-    },
-    "serve-static": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
-      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
-      "dev": true,
-      "requires": {
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "parseurl": "~1.3.3",
-        "send": "0.17.1"
-      }
-    },
-    "set-blocking": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
-      "dev": true
-    },
-    "set-immediate-shim": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
-      "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
-      "dev": true
-    },
-    "set-value": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
-      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^2.0.1",
-        "is-extendable": "^0.1.1",
-        "is-plain-object": "^2.0.3",
-        "split-string": "^3.0.1"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "setimmediate": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
-      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
-      "dev": true
-    },
-    "setprototypeof": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
-      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
-      "dev": true
-    },
-    "sha.js": {
-      "version": "2.4.11",
-      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
-      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "shallow-clone": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz",
-      "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==",
-      "dev": true,
-      "requires": {
-        "is-extendable": "^0.1.1",
-        "kind-of": "^5.0.0",
-        "mixin-object": "^2.0.1"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-          "dev": true
-        }
-      }
-    },
-    "shebang-command": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
-      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
-      "dev": true,
-      "requires": {
-        "shebang-regex": "^1.0.0"
-      }
-    },
-    "shebang-regex": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
-      "dev": true
-    },
-    "shelljs": {
-      "version": "0.8.4",
-      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz",
-      "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.0.0",
-        "interpret": "^1.0.0",
-        "rechoir": "^0.6.2"
-      }
-    },
-    "signal-exit": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
-      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
-      "dev": true
-    },
-    "slash": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
-      "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
-      "dev": true
-    },
-    "smart-buffer": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz",
-      "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==",
-      "dev": true
-    },
-    "snapdragon": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
-      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
-      "dev": true,
-      "requires": {
-        "base": "^0.11.1",
-        "debug": "^2.2.0",
-        "define-property": "^0.2.5",
-        "extend-shallow": "^2.0.1",
-        "map-cache": "^0.2.2",
-        "source-map": "^0.5.6",
-        "source-map-resolve": "^0.5.0",
-        "use": "^3.1.0"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "snapdragon-node": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
-      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
-      "dev": true,
-      "requires": {
-        "define-property": "^1.0.0",
-        "isobject": "^3.0.0",
-        "snapdragon-util": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
-    "snapdragon-util": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
-      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.2.0"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "socket.io": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz",
-      "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==",
-      "dev": true,
-      "requires": {
-        "debug": "~3.1.0",
-        "engine.io": "~3.2.0",
-        "has-binary2": "~1.0.2",
-        "socket.io-adapter": "~1.1.0",
-        "socket.io-client": "2.1.1",
-        "socket.io-parser": "~3.2.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        }
-      }
-    },
-    "socket.io-adapter": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
-      "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==",
-      "dev": true
-    },
-    "socket.io-client": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz",
-      "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==",
-      "dev": true,
-      "requires": {
-        "backo2": "1.0.2",
-        "base64-arraybuffer": "0.1.5",
-        "component-bind": "1.0.0",
-        "component-emitter": "1.2.1",
-        "debug": "~3.1.0",
-        "engine.io-client": "~3.2.0",
-        "has-binary2": "~1.0.2",
-        "has-cors": "1.1.0",
-        "indexof": "0.0.1",
-        "object-component": "0.0.3",
-        "parseqs": "0.0.5",
-        "parseuri": "0.0.5",
-        "socket.io-parser": "~3.2.0",
-        "to-array": "0.1.4"
-      },
-      "dependencies": {
-        "component-emitter": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
-          "dev": true
-        },
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        }
-      }
-    },
-    "socket.io-parser": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
-      "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
-      "dev": true,
-      "requires": {
-        "component-emitter": "1.2.1",
-        "debug": "~3.1.0",
-        "isarray": "2.0.1"
-      },
-      "dependencies": {
-        "component-emitter": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
-          "dev": true
-        },
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
-        "isarray": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
-          "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
-          "dev": true
-        }
-      }
-    },
-    "sockjs": {
-      "version": "0.3.19",
-      "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
-      "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
-      "dev": true,
-      "requires": {
-        "faye-websocket": "^0.10.0",
-        "uuid": "^3.0.1"
-      }
-    },
-    "sockjs-client": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz",
-      "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==",
-      "dev": true,
-      "requires": {
-        "debug": "^3.2.5",
-        "eventsource": "^1.0.7",
-        "faye-websocket": "~0.11.1",
-        "inherits": "^2.0.3",
-        "json3": "^3.3.2",
-        "url-parse": "^1.4.3"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.7",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "faye-websocket": {
-          "version": "0.11.3",
-          "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
-          "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
-          "dev": true,
-          "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
-        }
-      }
-    },
-    "socks": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz",
-      "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
-      "dev": true,
-      "requires": {
-        "ip": "1.1.5",
-        "smart-buffer": "^4.1.0"
-      }
-    },
-    "socks-proxy-agent": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz",
-      "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
-      "dev": true,
-      "requires": {
-        "agent-base": "~4.2.1",
-        "socks": "~2.3.2"
-      },
-      "dependencies": {
-        "agent-base": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
-          "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
-          "dev": true,
-          "requires": {
-            "es6-promisify": "^5.0.0"
-          }
-        }
-      }
-    },
-    "source-list-map": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
-      "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
-      "dev": true
-    },
-    "source-map": {
-      "version": "0.7.3",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-      "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-      "dev": true
-    },
-    "source-map-loader": {
-      "version": "0.2.4",
-      "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz",
-      "integrity": "sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ==",
-      "dev": true,
-      "requires": {
-        "async": "^2.5.0",
-        "loader-utils": "^1.1.0"
-      }
-    },
-    "source-map-resolve": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
-      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
-      "dev": true,
-      "requires": {
-        "atob": "^2.1.2",
-        "decode-uri-component": "^0.2.0",
-        "resolve-url": "^0.2.1",
-        "source-map-url": "^0.4.0",
-        "urix": "^0.1.0"
-      }
-    },
-    "source-map-support": {
-      "version": "0.5.10",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz",
-      "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==",
-      "dev": true,
-      "requires": {
-        "buffer-from": "^1.0.0",
-        "source-map": "^0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "source-map-url": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
-      "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
-      "dev": true
-    },
-    "sourcemap-codec": {
-      "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": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
-      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
-      "dev": true,
-      "requires": {
-        "spdx-expression-parse": "^3.0.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-exceptions": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
-      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
-      "dev": true
-    },
-    "spdx-expression-parse": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
-      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
-      "dev": true,
-      "requires": {
-        "spdx-exceptions": "^2.1.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-license-ids": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz",
-      "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==",
-      "dev": true
-    },
-    "spdy": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
-      "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
-      "dev": true,
-      "requires": {
-        "debug": "^4.1.0",
-        "handle-thing": "^2.0.0",
-        "http-deceiver": "^1.2.7",
-        "select-hose": "^2.0.0",
-        "spdy-transport": "^3.0.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "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": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
-      "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
-      "dev": true,
-      "requires": {
-        "debug": "^4.1.0",
-        "detect-node": "^2.0.4",
-        "hpack.js": "^2.1.6",
-        "obuf": "^1.1.2",
-        "readable-stream": "^3.0.6",
-        "wbuf": "^1.7.3"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "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.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",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
-          }
-        }
-      }
-    },
-    "speed-measure-webpack-plugin": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.0.tgz",
-      "integrity": "sha512-b9Yd0TrzceMVYSbuamM1sFsGM1oVfyFTM22gOoyLhymNvBVApuYpkdFOgYkKJpN/KhTpcCYcTGHg7X+FJ33Vvw==",
-      "dev": true,
-      "requires": {
-        "chalk": "^2.0.1"
-      }
-    },
-    "split-string": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
-      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^3.0.0"
-      }
-    },
-    "sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
-    },
-    "sshpk": {
-      "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",
-        "bcrypt-pbkdf": "^1.0.0",
-        "dashdash": "^1.12.0",
-        "ecc-jsbn": "~0.1.1",
-        "getpass": "^0.1.1",
-        "jsbn": "~0.1.0",
-        "safer-buffer": "^2.0.2",
-        "tweetnacl": "~0.14.0"
-      }
-    },
-    "ssri": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz",
-      "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "^5.1.1"
-      }
-    },
-    "static-extend": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
-      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
-      "dev": true,
-      "requires": {
-        "define-property": "^0.2.5",
-        "object-copy": "^0.1.0"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        }
-      }
-    },
-    "stats-webpack-plugin": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/stats-webpack-plugin/-/stats-webpack-plugin-0.7.0.tgz",
-      "integrity": "sha512-NT0YGhwuQ0EOX+uPhhUcI6/+1Sq/pMzNuSCBVT4GbFl/ac6I/JZefBcjlECNfAb1t3GOx5dEj1Z7x0cAxeeVLQ==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.4"
-      }
-    },
-    "statuses": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
-      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
-      "dev": true
-    },
-    "stdout-stream": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
-      "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "readable-stream": "^2.0.1"
-      }
-    },
-    "stream-browserify": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
-      "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
-      "dev": true,
-      "requires": {
-        "inherits": "~2.0.1",
-        "readable-stream": "^2.0.2"
-      }
-    },
-    "stream-each": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
-      "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.1.0",
-        "stream-shift": "^1.0.0"
-      }
-    },
-    "stream-http": {
-      "version": "2.8.3",
-      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
-      "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
-      "dev": true,
-      "requires": {
-        "builtin-status-codes": "^3.0.0",
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.3.6",
-        "to-arraybuffer": "^1.0.0",
-        "xtend": "^4.0.0"
-      }
-    },
-    "stream-shift": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
-      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
-      "dev": true
-    },
-    "streamroller": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz",
-      "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==",
-      "dev": true,
-      "requires": {
-        "async": "^2.6.2",
-        "date-format": "^2.0.0",
-        "debug": "^3.2.6",
-        "fs-extra": "^7.0.1",
-        "lodash": "^4.17.14"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.7",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-          "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
-        }
-      }
-    },
-    "string-width": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
-      "dev": true,
-      "requires": {
-        "code-point-at": "^1.0.0",
-        "is-fullwidth-code-point": "^1.0.0",
-        "strip-ansi": "^3.0.0"
-      }
-    },
-    "string.prototype.trimend": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
-      "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.0",
-        "define-properties": "^1.1.3"
-      }
-    },
-    "string.prototype.trimstart": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz",
-      "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.0",
-        "define-properties": "^1.1.3"
-      }
-    },
-    "string_decoder": {
-      "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"
-      }
-    },
-    "strip-ansi": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
-      "dev": true,
-      "requires": {
-        "ansi-regex": "^2.0.0"
-      }
-    },
-    "strip-bom": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
-      "dev": true,
-      "requires": {
-        "is-utf8": "^0.2.0"
-      }
-    },
-    "strip-eof": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
-      "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
-      "dev": true
-    },
-    "strip-indent": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
-      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "get-stdin": "^4.0.1"
-      }
-    },
-    "style-loader": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz",
-      "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.1.0",
-        "schema-utils": "^1.0.0"
-      }
-    },
-    "stylus": {
-      "version": "0.54.5",
-      "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz",
-      "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=",
-      "dev": true,
-      "requires": {
-        "css-parse": "1.7.x",
-        "debug": "*",
-        "glob": "7.0.x",
-        "mkdirp": "0.5.x",
-        "sax": "0.5.x",
-        "source-map": "0.1.x"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.0.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
-          "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.2",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "source-map": {
-          "version": "0.1.43",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
-          "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
-          "dev": true,
-          "requires": {
-            "amdefine": ">=0.0.4"
-          }
-        }
-      }
-    },
-    "stylus-loader": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz",
-      "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.0.2",
-        "lodash.clonedeep": "^4.5.0",
-        "when": "~3.6.x"
-      }
-    },
-    "supports-color": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
-      "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
-      "dev": true,
-      "requires": {
-        "has-flag": "^3.0.0"
-      }
-    },
-    "symbol-observable": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
-      "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
-      "dev": true
-    },
-    "tapable": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
-      "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
-      "dev": true
-    },
-    "tar": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
-      "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "block-stream": "*",
-        "fstream": "^1.0.12",
-        "inherits": "2"
-      }
-    },
-    "terser": {
-      "version": "3.17.0",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz",
-      "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==",
-      "dev": true,
-      "requires": {
-        "commander": "^2.19.0",
-        "source-map": "~0.6.1",
-        "source-map-support": "~0.5.10"
-      },
-      "dependencies": {
-        "commander": {
-          "version": "2.20.3",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "terser-webpack-plugin": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz",
-      "integrity": "sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==",
-      "dev": true,
-      "requires": {
-        "cacache": "^11.0.2",
-        "find-cache-dir": "^2.0.0",
-        "schema-utils": "^1.0.0",
-        "serialize-javascript": "^1.4.0",
-        "source-map": "^0.6.1",
-        "terser": "^3.16.1",
-        "webpack-sources": "^1.1.0",
-        "worker-farm": "^1.5.2"
-      },
-      "dependencies": {
-        "cacache": {
-          "version": "11.3.3",
-          "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz",
-          "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==",
-          "dev": true,
-          "requires": {
-            "bluebird": "^3.5.5",
-            "chownr": "^1.1.1",
-            "figgy-pudding": "^3.5.1",
-            "glob": "^7.1.4",
-            "graceful-fs": "^4.1.15",
-            "lru-cache": "^5.1.1",
-            "mississippi": "^3.0.0",
-            "mkdirp": "^0.5.1",
-            "move-concurrently": "^1.0.1",
-            "promise-inflight": "^1.0.1",
-            "rimraf": "^2.6.3",
-            "ssri": "^6.0.1",
-            "unique-filename": "^1.1.1",
-            "y18n": "^4.0.0"
-          }
-        },
-        "find-cache-dir": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
-          "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
-          "dev": true,
-          "requires": {
-            "commondir": "^1.0.1",
-            "make-dir": "^2.0.0",
-            "pkg-dir": "^3.0.0"
-          }
-        },
-        "find-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^3.0.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "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"
-          }
-        },
-        "locate-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^3.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "make-dir": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
-          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
-          "dev": true,
-          "requires": {
-            "pify": "^4.0.1",
-            "semver": "^5.6.0"
-          }
-        },
-        "mississippi": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
-          "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
-          "dev": true,
-          "requires": {
-            "concat-stream": "^1.5.0",
-            "duplexify": "^3.4.2",
-            "end-of-stream": "^1.1.0",
-            "flush-write-stream": "^1.0.0",
-            "from2": "^2.1.0",
-            "parallel-transform": "^1.1.0",
-            "pump": "^3.0.0",
-            "pumpify": "^1.3.3",
-            "stream-each": "^1.1.0",
-            "through2": "^2.0.0"
-          }
-        },
-        "p-limit": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.0.0"
-          }
-        },
-        "p-try": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-          "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-          "dev": true
-        },
-        "pify": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
-          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
-          "dev": true
-        },
-        "pkg-dir": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
-          "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
-          "dev": true,
-          "requires": {
-            "find-up": "^3.0.0"
-          }
-        },
-        "pump": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-          "dev": true,
-          "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "ssri": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
-          "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
-          "dev": true,
-          "requires": {
-            "figgy-pudding": "^3.5.1"
-          }
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
-        }
-      }
-    },
-    "through": {
-      "version": "2.3.8",
-      "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
-      "dev": true
-    },
-    "through2": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
-      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
-      "dev": true,
-      "requires": {
-        "readable-stream": "~2.3.6",
-        "xtend": "~4.0.1"
-      }
-    },
-    "thunky": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
-      "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
-      "dev": true
-    },
-    "timers-browserify": {
-      "version": "2.0.12",
-      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
-      "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
-      "dev": true,
-      "requires": {
-        "setimmediate": "^1.0.4"
-      }
-    },
-    "tiny-emitter": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
-      "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
-      "optional": true
-    },
-    "tmp": {
-      "version": "0.0.33",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
-      "dev": true,
-      "requires": {
-        "os-tmpdir": "~1.0.2"
-      }
-    },
-    "to-array": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
-      "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
-      "dev": true
-    },
-    "to-arraybuffer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
-      "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
-      "dev": true
-    },
-    "to-fast-properties": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
-      "dev": true
-    },
-    "to-object-path": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
-      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "to-regex": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
-      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
-      "dev": true,
-      "requires": {
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "regex-not": "^1.0.2",
-        "safe-regex": "^1.1.0"
-      }
-    },
-    "to-regex-range": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
-      "dev": true,
-      "requires": {
-        "is-number": "^3.0.0",
-        "repeat-string": "^1.6.1"
-      }
-    },
-    "toidentifier": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
-      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
-      "dev": true
-    },
-    "tough-cookie": {
-      "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.28",
-        "punycode": "^2.1.1"
-      }
-    },
-    "trait-ontology-widget": {
-      "version": "git+https://github.com/gnpis/trait-ontology-widget.git#6db245aa78ab66628ecd1897e349f3d92e9a2006",
-      "from": "git+https://github.com/gnpis/trait-ontology-widget.git#v2.2.1",
-      "requires": {
-        "jquery": "3.3.1",
-        "jstree": "3.3.5"
-      },
-      "dependencies": {
-        "jquery": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
-          "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
-        }
-      }
-    },
-    "tree-kill": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz",
-      "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==",
-      "dev": true
-    },
-    "trim-newlines": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
-      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
-      "dev": true,
-      "optional": true
-    },
-    "trim-right": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
-      "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
-      "dev": true
-    },
-    "true-case-path": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
-      "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "glob": "^7.1.2"
-      }
-    },
-    "ts-node": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz",
-      "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==",
-      "dev": true,
-      "requires": {
-        "arrify": "^1.0.0",
-        "buffer-from": "^1.1.0",
-        "diff": "^3.1.0",
-        "make-error": "^1.1.1",
-        "minimist": "^1.2.0",
-        "mkdirp": "^0.5.1",
-        "source-map-support": "^0.5.6",
-        "yn": "^2.0.0"
-      }
-    },
-    "tslib": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz",
-      "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg=="
-    },
-    "tslint": {
-      "version": "5.11.0",
-      "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz",
-      "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=",
-      "dev": true,
-      "requires": {
-        "babel-code-frame": "^6.22.0",
-        "builtin-modules": "^1.1.1",
-        "chalk": "^2.3.0",
-        "commander": "^2.12.1",
-        "diff": "^3.2.0",
-        "glob": "^7.1.1",
-        "js-yaml": "^3.7.0",
-        "minimatch": "^3.0.4",
-        "resolve": "^1.3.2",
-        "semver": "^5.3.0",
-        "tslib": "^1.8.0",
-        "tsutils": "^2.27.2"
-      }
-    },
-    "tslint-eslint-rules": {
-      "version": "5.4.0",
-      "resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz",
-      "integrity": "sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==",
-      "dev": true,
-      "requires": {
-        "doctrine": "0.7.2",
-        "tslib": "1.9.0",
-        "tsutils": "^3.0.0"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "1.9.0",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
-          "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==",
-          "dev": true
-        },
-        "tsutils": {
-          "version": "3.8.0",
-          "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.8.0.tgz",
-          "integrity": "sha512-XQdPhgcoTbCD8baXC38PQ0vpTZ8T3YrE+vR66YIj/xvDt1//8iAhafpIT/4DmvzzC1QFapEImERu48Pa01dIUA==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.8.1"
-          }
-        }
-      }
-    },
-    "tsutils": {
-      "version": "2.29.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
-      "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.8.1"
-      }
-    },
-    "tty-browserify": {
-      "version": "0.0.0",
-      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
-      "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
-      "dev": true
-    },
-    "tunnel-agent": {
-      "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"
-      }
-    },
-    "tweetnacl": {
-      "version": "0.14.5",
-      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
-      "dev": true
-    },
-    "type-is": {
-      "version": "1.6.18",
-      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
-      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
-      "dev": true,
-      "requires": {
-        "media-typer": "0.3.0",
-        "mime-types": "~2.1.24"
-      }
-    },
-    "typedarray": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
-      "dev": true
-    },
-    "typescript": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz",
-      "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==",
-      "dev": true
-    },
-    "ultron": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
-      "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
-      "dev": true
-    },
-    "union-value": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
-      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
-      "dev": true,
-      "requires": {
-        "arr-union": "^3.1.0",
-        "get-value": "^2.0.6",
-        "is-extendable": "^0.1.1",
-        "set-value": "^2.0.1"
-      }
-    },
-    "unique-filename": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
-      "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
-      "dev": true,
-      "requires": {
-        "unique-slug": "^2.0.0"
-      }
-    },
-    "unique-slug": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
-      "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
-      "dev": true,
-      "requires": {
-        "imurmurhash": "^0.1.4"
-      }
-    },
-    "universalify": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
-      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
-      "dev": true
-    },
-    "unpipe": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
-      "dev": true
-    },
-    "unset-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
-      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
-      "dev": true,
-      "requires": {
-        "has-value": "^0.3.1",
-        "isobject": "^3.0.0"
-      },
-      "dependencies": {
-        "has-value": {
-          "version": "0.3.1",
-          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
-          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
-          "dev": true,
-          "requires": {
-            "get-value": "^2.0.3",
-            "has-values": "^0.1.4",
-            "isobject": "^2.0.0"
-          },
-          "dependencies": {
-            "isobject": {
-              "version": "2.1.0",
-              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
-              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
-              "dev": true,
-              "requires": {
-                "isarray": "1.0.0"
-              }
-            }
-          }
-        },
-        "has-values": {
-          "version": "0.1.4",
-          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
-          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
-          "dev": true
-        }
-      }
-    },
-    "upath": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
-      "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
-      "dev": true
-    },
-    "uri-js": {
-      "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"
-      }
-    },
-    "urix": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
-      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
-      "dev": true
-    },
-    "url": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
-      "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
-      "dev": true,
-      "requires": {
-        "punycode": "1.3.2",
-        "querystring": "0.2.0"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.3.2",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
-          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
-          "dev": true
-        }
-      }
-    },
-    "url-parse": {
-      "version": "1.4.7",
-      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
-      "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
-      "dev": true,
-      "requires": {
-        "querystringify": "^2.1.1",
-        "requires-port": "^1.0.0"
-      }
-    },
-    "use": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
-      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
-      "dev": true
-    },
-    "useragent": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
-      "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==",
-      "dev": true,
-      "requires": {
-        "lru-cache": "4.1.x",
-        "tmp": "0.0.x"
-      }
-    },
-    "util": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
-      "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
-      "dev": true,
-      "requires": {
-        "inherits": "2.0.3"
-      }
-    },
-    "util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
-      "dev": true
-    },
-    "utils-merge": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
-      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
-      "dev": true
-    },
-    "uuid": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
-      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
-      "dev": true
-    },
-    "validate-npm-package-license": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
-      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
-      "dev": true,
-      "requires": {
-        "spdx-correct": "^3.0.0",
-        "spdx-expression-parse": "^3.0.0"
-      }
-    },
-    "validate-npm-package-name": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
-      "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
-      "dev": true,
-      "requires": {
-        "builtins": "^1.0.3"
-      }
-    },
-    "vary": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
-      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
-      "dev": true
-    },
-    "verror": {
-      "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",
-        "extsprintf": "^1.2.0"
-      }
-    },
-    "vm-browserify": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
-      "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
-      "dev": true
-    },
-    "void-elements": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
-      "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
-      "dev": true
-    },
-    "watchpack": {
-      "version": "1.7.5",
-      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
-      "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
-      "dev": true,
-      "requires": {
-        "chokidar": "^3.4.1",
-        "graceful-fs": "^4.1.2",
-        "neo-async": "^2.5.0",
-        "watchpack-chokidar2": "^2.0.1"
-      },
-      "dependencies": {
-        "anymatch": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
-          "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "normalize-path": "^3.0.0",
-            "picomatch": "^2.0.4"
-          }
-        },
-        "binary-extensions": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
-          "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
-          "dev": true,
-          "optional": true
-        },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "chokidar": {
-          "version": "3.4.3",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
-          "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "anymatch": "~3.1.1",
-            "braces": "~3.0.2",
-            "fsevents": "~2.1.2",
-            "glob-parent": "~5.1.0",
-            "is-binary-path": "~2.1.0",
-            "is-glob": "~4.0.1",
-            "normalize-path": "~3.0.0",
-            "readdirp": "~3.5.0"
-          }
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "fsevents": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
-          "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
-          "dev": true,
-          "optional": true
-        },
-        "glob-parent": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
-          "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        },
-        "is-binary-path": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-          "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "binary-extensions": "^2.0.0"
-          }
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true,
-          "optional": true
-        },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-          "dev": true
-        },
-        "readdirp": {
-          "version": "3.5.0",
-          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
-          "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "picomatch": "^2.2.1"
-          }
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
-        }
-      }
-    },
-    "watchpack-chokidar2": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
-      "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "chokidar": "^2.1.8"
-      },
-      "dependencies": {
-        "chokidar": {
-          "version": "2.1.8",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
-          "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "anymatch": "^2.0.0",
-            "async-each": "^1.0.1",
-            "braces": "^2.3.2",
-            "fsevents": "^1.2.7",
-            "glob-parent": "^3.1.0",
-            "inherits": "^2.0.3",
-            "is-binary-path": "^1.0.0",
-            "is-glob": "^4.0.0",
-            "normalize-path": "^3.0.0",
-            "path-is-absolute": "^1.0.0",
-            "readdirp": "^2.2.1",
-            "upath": "^1.1.1"
-          }
-        },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "wbuf": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
-      "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
-      "dev": true,
-      "requires": {
-        "minimalistic-assert": "^1.0.0"
-      }
-    },
-    "webdriver-js-extender": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz",
-      "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==",
-      "dev": true,
-      "requires": {
-        "@types/selenium-webdriver": "^3.0.0",
-        "selenium-webdriver": "^3.0.1"
-      }
-    },
-    "webpack": {
-      "version": "4.29.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.0.tgz",
-      "integrity": "sha512-pxdGG0keDBtamE1mNvT5zyBdx+7wkh6mh7uzMOo/uRQ/fhsdj5FXkh/j5mapzs060forql1oXqXN9HJGju+y7w==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.7.11",
-        "@webassemblyjs/helper-module-context": "1.7.11",
-        "@webassemblyjs/wasm-edit": "1.7.11",
-        "@webassemblyjs/wasm-parser": "1.7.11",
-        "acorn": "^6.0.5",
-        "acorn-dynamic-import": "^4.0.0",
-        "ajv": "^6.1.0",
-        "ajv-keywords": "^3.1.0",
-        "chrome-trace-event": "^1.0.0",
-        "enhanced-resolve": "^4.1.0",
-        "eslint-scope": "^4.0.0",
-        "json-parse-better-errors": "^1.0.2",
-        "loader-runner": "^2.3.0",
-        "loader-utils": "^1.1.0",
-        "memory-fs": "~0.4.1",
-        "micromatch": "^3.1.8",
-        "mkdirp": "~0.5.0",
-        "neo-async": "^2.5.0",
-        "node-libs-browser": "^2.0.0",
-        "schema-utils": "^0.4.4",
-        "tapable": "^1.1.0",
-        "terser-webpack-plugin": "^1.1.0",
-        "watchpack": "^1.5.0",
-        "webpack-sources": "^1.3.0"
-      },
-      "dependencies": {
-        "schema-utils": {
-          "version": "0.4.7",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
-          "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
-          "dev": true,
-          "requires": {
-            "ajv": "^6.1.0",
-            "ajv-keywords": "^3.1.0"
-          }
-        }
-      }
-    },
-    "webpack-core": {
-      "version": "0.6.9",
-      "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
-      "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=",
-      "dev": true,
-      "requires": {
-        "source-list-map": "~0.1.7",
-        "source-map": "~0.4.1"
-      },
-      "dependencies": {
-        "source-list-map": {
-          "version": "0.1.8",
-          "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz",
-          "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.4.4",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
-          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
-          "dev": true,
-          "requires": {
-            "amdefine": ">=0.0.4"
-          }
-        }
-      }
-    },
-    "webpack-dev-middleware": {
-      "version": "3.5.1",
-      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.5.1.tgz",
-      "integrity": "sha512-4dwCh/AyMOYAybggUr8fiCkRnjVDp+Cqlr9c+aaNB3GJYgRGYQWJ1YX/WAKUNA9dPNHZ6QSN2lYDKqjKSI8Vqw==",
-      "dev": true,
-      "requires": {
-        "memory-fs": "~0.4.1",
-        "mime": "^2.3.1",
-        "range-parser": "^1.0.3",
-        "webpack-log": "^2.0.0"
-      },
-      "dependencies": {
-        "mime": {
-          "version": "2.4.6",
-          "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
-          "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
-          "dev": true
-        }
-      }
-    },
-    "webpack-dev-server": {
-      "version": "3.1.14",
-      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz",
-      "integrity": "sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ==",
-      "dev": true,
-      "requires": {
-        "ansi-html": "0.0.7",
-        "bonjour": "^3.5.0",
-        "chokidar": "^2.0.0",
-        "compression": "^1.5.2",
-        "connect-history-api-fallback": "^1.3.0",
-        "debug": "^3.1.0",
-        "del": "^3.0.0",
-        "express": "^4.16.2",
-        "html-entities": "^1.2.0",
-        "http-proxy-middleware": "~0.18.0",
-        "import-local": "^2.0.0",
-        "internal-ip": "^3.0.1",
-        "ip": "^1.1.5",
-        "killable": "^1.0.0",
-        "loglevel": "^1.4.1",
-        "opn": "^5.1.0",
-        "portfinder": "^1.0.9",
-        "schema-utils": "^1.0.0",
-        "selfsigned": "^1.9.1",
-        "semver": "^5.6.0",
-        "serve-index": "^1.7.2",
-        "sockjs": "0.3.19",
-        "sockjs-client": "1.3.0",
-        "spdy": "^4.0.0",
-        "strip-ansi": "^3.0.0",
-        "supports-color": "^5.1.0",
-        "url": "^0.11.0",
-        "webpack-dev-middleware": "3.4.0",
-        "webpack-log": "^2.0.0",
-        "yargs": "12.0.2"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
-        "camelcase": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
-          "dev": true
-        },
-        "cliui": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
-          "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
-          "dev": true,
-          "requires": {
-            "string-width": "^2.1.1",
-            "strip-ansi": "^4.0.0",
-            "wrap-ansi": "^2.0.0"
-          },
-          "dependencies": {
-            "strip-ansi": {
-              "version": "4.0.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-              "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-              "dev": true,
-              "requires": {
-                "ansi-regex": "^3.0.0"
-              }
-            }
-          }
-        },
-        "cross-spawn": {
-          "version": "6.0.5",
-          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
-          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
-          "dev": true,
-          "requires": {
-            "nice-try": "^1.0.4",
-            "path-key": "^2.0.1",
-            "semver": "^5.5.0",
-            "shebang-command": "^1.2.0",
-            "which": "^1.2.9"
-          }
-        },
-        "debug": {
-          "version": "3.2.7",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "decamelize": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz",
-          "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==",
-          "dev": true,
-          "requires": {
-            "xregexp": "4.0.0"
-          }
-        },
-        "execa": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
-          "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
-          "dev": true,
-          "requires": {
-            "cross-spawn": "^6.0.0",
-            "get-stream": "^4.0.0",
-            "is-stream": "^1.1.0",
-            "npm-run-path": "^2.0.0",
-            "p-finally": "^1.0.0",
-            "signal-exit": "^3.0.0",
-            "strip-eof": "^1.0.0"
-          }
-        },
-        "find-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^3.0.0"
-          }
-        },
-        "get-stream": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
-          "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
-          "dev": true,
-          "requires": {
-            "pump": "^3.0.0"
-          }
-        },
-        "invert-kv": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
-          "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "lcid": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
-          "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
-          "dev": true,
-          "requires": {
-            "invert-kv": "^2.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^3.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "mime": {
-          "version": "2.4.6",
-          "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
-          "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
-          "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
-        },
-        "os-locale": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
-          "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
-          "dev": true,
-          "requires": {
-            "execa": "^1.0.0",
-            "lcid": "^2.0.0",
-            "mem": "^4.0.0"
-          }
-        },
-        "p-limit": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.0.0"
-          }
-        },
-        "p-try": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-          "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-          "dev": true
-        },
-        "pump": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-          "dev": true,
-          "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
-          }
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-          "dev": true,
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          },
-          "dependencies": {
-            "strip-ansi": {
-              "version": "4.0.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-              "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-              "dev": true,
-              "requires": {
-                "ansi-regex": "^3.0.0"
-              }
-            }
-          }
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        },
-        "webpack-dev-middleware": {
-          "version": "3.4.0",
-          "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz",
-          "integrity": "sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==",
-          "dev": true,
-          "requires": {
-            "memory-fs": "~0.4.1",
-            "mime": "^2.3.1",
-            "range-parser": "^1.0.3",
-            "webpack-log": "^2.0.0"
-          }
-        },
-        "which-module": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-          "dev": true
-        },
-        "yargs": {
-          "version": "12.0.2",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz",
-          "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==",
-          "dev": true,
-          "requires": {
-            "cliui": "^4.0.0",
-            "decamelize": "^2.0.0",
-            "find-up": "^3.0.0",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^3.0.0",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^2.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^3.2.1 || ^4.0.0",
-            "yargs-parser": "^10.1.0"
-          }
-        },
-        "yargs-parser": {
-          "version": "10.1.0",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
-          "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
-          "dev": true,
-          "requires": {
-            "camelcase": "^4.1.0"
-          }
-        }
-      }
-    },
-    "webpack-log": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
-      "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
-      "dev": true,
-      "requires": {
-        "ansi-colors": "^3.0.0",
-        "uuid": "^3.3.2"
-      }
-    },
-    "webpack-merge": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz",
-      "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.5"
-      }
-    },
-    "webpack-sources": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz",
-      "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==",
-      "dev": true,
-      "requires": {
-        "source-list-map": "^2.0.0",
-        "source-map": "~0.6.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "webpack-subresource-integrity": {
-      "version": "1.1.0-rc.6",
-      "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz",
-      "integrity": "sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w==",
-      "dev": true,
-      "requires": {
-        "webpack-core": "^0.6.8"
-      }
-    },
-    "websocket-driver": {
-      "version": "0.7.4",
-      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
-      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
-      "dev": true,
-      "requires": {
-        "http-parser-js": ">=0.5.1",
-        "safe-buffer": ">=5.1.0",
-        "websocket-extensions": ">=0.1.1"
-      }
-    },
-    "websocket-extensions": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
-      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
-      "dev": true
-    },
-    "when": {
-      "version": "3.6.4",
-      "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz",
-      "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=",
-      "dev": true
-    },
-    "which": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
-      "dev": true,
-      "requires": {
-        "isexe": "^2.0.0"
-      }
-    },
-    "which-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
-      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
-      "dev": true,
-      "optional": true
-    },
-    "wide-align": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
-      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
-      "dev": true,
-      "requires": {
-        "string-width": "^1.0.2 || 2"
-      }
-    },
-    "wordwrap": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
-      "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
-      "dev": true
-    },
-    "worker-farm": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
-      "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
-      "dev": true,
-      "requires": {
-        "errno": "~0.1.7"
-      }
-    },
-    "wrap-ansi": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
-      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
-      "dev": true,
-      "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1"
-      }
-    },
-    "wrappy": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-      "dev": true
-    },
-    "ws": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
-      "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
-      "dev": true,
-      "requires": {
-        "async-limiter": "~1.0.0",
-        "safe-buffer": "~5.1.0",
-        "ultron": "~1.1.0"
-      }
-    },
-    "xml2js": {
-      "version": "0.4.23",
-      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
-      "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
-      "dev": true,
-      "requires": {
-        "sax": ">=0.6.0",
-        "xmlbuilder": "~11.0.0"
-      },
-      "dependencies": {
-        "sax": {
-          "version": "1.2.4",
-          "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
-          "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
-          "dev": true
-        },
-        "xmlbuilder": {
-          "version": "11.0.1",
-          "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
-          "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
-          "dev": true
-        }
-      }
-    },
-    "xmlbuilder": {
-      "version": "12.0.0",
-      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-12.0.0.tgz",
-      "integrity": "sha512-lMo8DJ8u6JRWp0/Y4XLa/atVDr75H9litKlb2E5j3V3MesoL50EBgZDWoLT3F/LztVnG67GjPXLZpqcky/UMnQ==",
-      "dev": true
-    },
-    "xmlhttprequest-ssl": {
-      "version": "1.5.5",
-      "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
-      "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
-      "dev": true
-    },
-    "xregexp": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz",
-      "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==",
-      "dev": true
-    },
-    "xtend": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
-      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
-      "dev": true
-    },
-    "y18n": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-      "dev": true
-    },
-    "yallist": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
-      "dev": true
-    },
-    "yargs": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz",
-      "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "camelcase": "^3.0.0",
-        "cliui": "^3.2.0",
-        "decamelize": "^1.1.1",
-        "get-caller-file": "^1.0.1",
-        "os-locale": "^1.4.0",
-        "read-pkg-up": "^1.0.1",
-        "require-directory": "^2.1.1",
-        "require-main-filename": "^1.0.1",
-        "set-blocking": "^2.0.0",
-        "string-width": "^1.0.2",
-        "which-module": "^1.0.0",
-        "y18n": "^3.2.1",
-        "yargs-parser": "5.0.0-security.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true,
-          "optional": true
-        },
-        "y18n": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-          "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "yargs-parser": {
-      "version": "5.0.0-security.0",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz",
-      "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "camelcase": "^3.0.0",
-        "object.assign": "^4.1.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "yeast": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
-      "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
-      "dev": true
-    },
-    "yn": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
-      "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=",
-      "dev": true
-    },
-    "zone.js": {
-      "version": "0.8.29",
-      "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.29.tgz",
-      "integrity": "sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ=="
-    }
-  }
-}
diff --git a/frontend/package.json b/frontend/package.json
deleted file mode 100644
index ede9a6cce54a2b3f8b4d7139a8847be390f2e426..0000000000000000000000000000000000000000
--- a/frontend/package.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
-  "name": "frontend",
-  "version": "0.0.0",
-  "scripts": {
-    "ng": "ng",
-    "start": "ng serve",
-    "build": "ng build --prod",
-    "test": "ng test --code-coverage --no-progress --no-watch",
-    "test-multi-browsers": "ng test --code-coverage --no-progress --no-watch -c test-multi-browsers",
-    "lint": "ng lint",
-    "e2e": "ng e2e"
-  },
-  "private": true,
-  "dependencies": {
-    "@angular/animations": "7.2.7",
-    "@angular/common": "7.2.7",
-    "@angular/compiler": "7.2.7",
-    "@angular/core": "7.2.7",
-    "@angular/forms": "7.2.7",
-    "@angular/http": "7.2.7",
-    "@angular/platform-browser": "7.2.7",
-    "@angular/platform-browser-dynamic": "7.2.7",
-    "@angular/router": "7.2.7",
-    "@ng-bootstrap/ng-bootstrap": "4.2.2",
-    "@types/leaflet": "1.2.14",
-    "@types/leaflet.markercluster": "1.0.3",
-    "angular-coordinates": "1.0.0",
-    "angular-mocks": "1.7.8",
-    "bootstrap": "4.3.1",
-    "core-js": "2.5.7",
-    "file-saver": "2.0.2",
-    "font-awesome": "4.7.0",
-    "leaflet": "1.3.4",
-    "leaflet.markercluster": "1.4.1",
-    "moment": "2.24.0",
-    "ng-mocks": "7.6.0",
-    "ngx-markdown": "8.2.1",
-    "ngx-moment": "3.3.0",
-    "popper.js": "1.14.6",
-    "rxjs": "6.4.0",
-    "trait-ontology-widget": "git+https://github.com/gnpis/trait-ontology-widget.git#v2.2.1",
-    "tslib": "1.11.0",
-    "zone.js": "0.8.29"
-  },
-  "devDependencies": {
-    "@angular-devkit/build-angular": "0.13.2",
-    "@angular/cli": "7.3.4",
-    "@angular/compiler-cli": "7.2.7",
-    "@angular/language-service": "7.2.7",
-    "@types/jasmine": "2.8.12",
-    "@types/jasminewd2": "2.0.6",
-    "@types/node": "8.9.5",
-    "ajv": "6.9.1",
-    "codelyzer": "5.2.2",
-    "jasmine-core": "3.5.0",
-    "jasmine-spec-reporter": "5.0.1",
-    "karma": "4.4.1",
-    "karma-chrome-launcher": "3.1.0",
-    "karma-coverage-istanbul-reporter": "2.1.1",
-    "karma-firefox-launcher": "1.3.0",
-    "karma-jasmine": "3.1.1",
-    "karma-jasmine-html-reporter": "1.5.3",
-    "karma-junit-reporter": "2.0.1",
-    "ngx-speculoos": "1.1.0",
-    "protractor": "5.4.1",
-    "ts-node": "7.0.1",
-    "tslint": "5.11.0",
-    "tslint-eslint-rules": "5.4.0",
-    "typescript": "3.2.4"
-  }
-}
diff --git a/frontend/proxy.conf.js b/frontend/proxy.conf.js
deleted file mode 100644
index 771e4ce755ca18e4dae8e8dcf203a664435ce047..0000000000000000000000000000000000000000
--- a/frontend/proxy.conf.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const PROXY_CONFIG = [
-    {
-        context: [
-            "/faidare-dev/brapi",
-            "/faidare-dev/faidare",
-        ],
-        target: "http://localhost:8380",
-        secure: false
-    }
-];
-
-module.exports = PROXY_CONFIG;
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
deleted file mode 100644
index 01ef7b6a7388a041723ef7463758aacd5e1f25dc..0000000000000000000000000000000000000000
--- a/frontend/src/app/app-routing.module.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { NgModule } from '@angular/core';
-import { RouterModule, Routes } from '@angular/router';
-import { ResultPageComponent } from './result-page/result-page.component';
-import { GermplasmCardComponent } from './germplasm-card/germplasm-card.component';
-import { StudyCardComponent } from './study-card/study-card.component';
-import { SiteCardComponent } from './site-card/site-card.component';
-import { MarkdownPageComponent } from './markdown-page/markdown-page.component';
-import { environment } from '../environments/environment';
-import { GermplasmResultPageComponent } from './germplasm-result-page/germplasm-result-page.component';
-
-export const routes: Routes = [
-    { path: 'studies/:id', component: StudyCardComponent },
-    { path: 'sites/:id', component: SiteCardComponent },
-    { path: '', component: ResultPageComponent },
-    { path: 'germplasm', component: GermplasmCardComponent },
-    { path: 'germplasm-result-page', component: GermplasmResultPageComponent },
-    { path: 'about', component: MarkdownPageComponent, data: { mdFile: environment.aboutUsMdFile } },
-    { path: 'join', component: MarkdownPageComponent, data: { mdFile: environment.joinUsMdFile } },
-    { path: 'legal', component: MarkdownPageComponent, data: { mdFile: environment.legalMentionsMdFile } },
-    { path: 'help', component: MarkdownPageComponent, data: { mdFile: environment.helpMdFile } },
-    { path: 'HOW-TO-JOIN.md', redirectTo: '/join' },
-
-];
-
-@NgModule({
-    imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
-    exports: [RouterModule]
-})
-export class AppRoutingModule {
-}
diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html
deleted file mode 100644
index e56bebd4c869ad6afbe5836c72441b80575e1ab8..0000000000000000000000000000000000000000
--- a/frontend/src/app/app.component.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<faidare-navbar></faidare-navbar>
-<div style="margin-top: 100px ; margin-right: 100px ; margin-left: 100px">
-  <faidare-error></faidare-error>
-  <router-outlet></router-outlet>
-</div>
-
diff --git a/frontend/src/app/app.component.scss b/frontend/src/app/app.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/frontend/src/app/app.component.spec.ts b/frontend/src/app/app.component.spec.ts
deleted file mode 100644
index f639559d3b8ffc505d88e81d0b3ffc7ef0efa1fd..0000000000000000000000000000000000000000
--- a/frontend/src/app/app.component.spec.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-import { RouterTestingModule } from '@angular/router/testing';
-import { AppComponent } from './app.component';
-import { NavbarComponent } from './navbar/navbar.component';
-import { ErrorComponent } from './error/error.component';
-import { HttpClientTestingModule } from '@angular/common/http/testing';
-
-describe('AppComponent', () => {
-    beforeEach(() => TestBed.configureTestingModule({
-        imports: [RouterTestingModule, HttpClientTestingModule],
-        declarations: [AppComponent, ErrorComponent, NavbarComponent]
-    }));
-
-    it('should create the app', () => {
-        const fixture = TestBed.createComponent(AppComponent);
-        const app = fixture.debugElement.componentInstance;
-        expect(app).toBeTruthy();
-    });
-});
diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts
deleted file mode 100644
index 222abac5daf61d27b04d52f1a7fecf0342de8acc..0000000000000000000000000000000000000000
--- a/frontend/src/app/app.component.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Component } from '@angular/core';
-
-@Component({
-    selector: 'faidare-root',
-    templateUrl: './app.component.html',
-    styleUrls: ['./app.component.scss']
-})
-export class AppComponent {
-    title = 'frontend';
-}
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
deleted file mode 100644
index ba96c6c987c4ffb83052ea085197037a2695ef8f..0000000000000000000000000000000000000000
--- a/frontend/src/app/app.module.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import { BrowserModule } from '@angular/platform-browser';
-import { NgModule } from '@angular/core';
-import { AppRoutingModule } from './app-routing.module';
-import { AppComponent } from './app.component';
-import { FormComponent } from './form/form.component';
-import { ResultPageComponent } from './result-page/result-page.component';
-import { GermplasmCardComponent } from './germplasm-card/germplasm-card.component';
-import { GermplasmResultPageComponent } from './germplasm-result-page/germplasm-result-page.component';
-import { StudyCardComponent } from './study-card/study-card.component';
-import { SiteCardComponent } from './site-card/site-card.component';
-import {
-    HTTP_INTERCEPTORS,
-    HttpClient,
-    HttpClientModule
-} from '@angular/common/http';
-import { NavbarComponent } from './navbar/navbar.component';
-import { MapComponent } from './map/map.component';
-import {
-    NgbAlertModule,
-    NgbDropdownModule,
-    NgbPaginationModule,
-    NgbPopoverModule,
-    NgbTypeaheadModule
-} from '@ng-bootstrap/ng-bootstrap';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { SuggestionFieldComponent } from './form/suggestion-field/suggestion-field.component';
-import { DocumentComponent } from './result-page/document/document.component';
-import { ErrorComponent } from './error/error.component';
-import { ErrorInterceptorService } from './error-interceptor.service';
-import { TraitOntologyWidgetComponent } from './form/trait-ontology-widget/trait-ontology-widget.component';
-import { FacetsComponent } from './facets/facets.component';
-import { CardRowComponent } from './card-row/card-row.component';
-import { CardSectionComponent } from './card-section/card-section.component';
-import { LoadingSpinnerComponent } from './loading-spinner/loading-spinner.component';
-import { CardTableComponent } from './card-table/card-table.component';
-import { MomentModule } from 'ngx-moment';
-import { XrefsComponent } from './xrefs/xrefs.component';
-import { CoordinatesModule } from 'angular-coordinates';
-import { CardGenericDocumentComponent } from './card-generic-document/card-generic-document.component';
-import { MarkdownModule, MarkedOptions, MarkedRenderer } from 'ngx-markdown';
-import { MarkdownPageComponent } from './markdown-page/markdown-page.component';
-import { DecimalPipe } from '@angular/common';
-import { LargeFacetsComponent } from './facets/large-facets/large-facets.component';
-import { SmallFacetsComponent } from './facets/small-facets/small-facets.component';
-import { SwitchButtonComponent } from './facets/switch-button/switch-button.component';
-
-@NgModule({
-    declarations: [
-        AppComponent,
-        FormComponent,
-        ResultPageComponent,
-        GermplasmCardComponent,
-        GermplasmResultPageComponent,
-        GermplasmResultPageComponent,
-        StudyCardComponent,
-        SiteCardComponent,
-        NavbarComponent,
-        MapComponent,
-        SuggestionFieldComponent,
-        DocumentComponent,
-        ErrorComponent,
-        TraitOntologyWidgetComponent,
-        FacetsComponent,
-        CardRowComponent,
-        CardSectionComponent,
-        LoadingSpinnerComponent,
-        CardTableComponent,
-        XrefsComponent,
-        CardGenericDocumentComponent,
-        MarkdownPageComponent,
-        LargeFacetsComponent,
-        SmallFacetsComponent,
-        SwitchButtonComponent
-    ],
-    imports: [
-        BrowserModule,
-        AppRoutingModule,
-        HttpClientModule,
-        NgbTypeaheadModule,
-        NgbPaginationModule,
-        NgbAlertModule,
-        NgbDropdownModule,
-        NgbPopoverModule,
-        FormsModule,
-        ReactiveFormsModule,
-        MomentModule,
-        CoordinatesModule,
-        MarkdownModule.forRoot({
-            loader: HttpClient, // optional, only if you use [src] attribute
-            markedOptions: {
-                provide: MarkedOptions,
-                useFactory: markedOptionsFactory,
-                useValue: {
-                    gfm: true, // default
-                    tables: true,
-                    breaks: false,
-                    pedantic: false,
-                    sanitize: false,
-                    smartLists: true,
-                    smartypants: false
-                },
-            }
-        }),
-
-    ],
-    providers: [
-        {
-            provide: HTTP_INTERCEPTORS,
-            useExisting: ErrorInterceptorService,
-            multi: true
-        },
-        DecimalPipe
-    ],
-    bootstrap: [AppComponent]
-})
-export class AppModule {
-}
-
-export function markedOptionsFactory(): MarkedOptions {
-
-    const renderer = new MarkedRenderer();
-
-    renderer.link = (href: string, title: string, text: string) => {
-        if (href.startsWith('#')) {
-            const fragment = href.split('#')[1];
-            return `<a href='${location.pathname}#${fragment}'>${text}</a>`;
-        }
-        return `<a href="${href}" target="_blank" >${text}</a>`;
-    };
-    return {
-        renderer: renderer
-    };
-}
diff --git a/frontend/src/app/brapi.service.spec.ts b/frontend/src/app/brapi.service.spec.ts
deleted file mode 100644
index 521ac19c2866e62618d5153a4660e40b42befa12..0000000000000000000000000000000000000000
--- a/frontend/src/app/brapi.service.spec.ts
+++ /dev/null
@@ -1,538 +0,0 @@
-import { BrapiService } from './brapi.service';
-import {
-    BrapiCollectingSite,
-    BrapiContacts,
-    BrapiGermplasm,
-    BrapiGermplasmAttributes,
-    BrapiGermplasmMcpd,
-    BrapiGermplasmPedigree,
-    BrapiGermplasmProgeny,
-    BrapiInstitute,
-    BrapiLocation,
-    BrapiObservationVariable,
-    BrapiProgeny,
-    BrapiResult,
-    BrapiResults,
-    BrapiSibling,
-    BrapiStudy,
-    BrapiTrial
-} from './models/brapi.model';
-import {
-    HttpClientTestingModule,
-    HttpTestingController
-} from '@angular/common/http/testing';
-import { TestBed } from '@angular/core/testing';
-import {
-    Donor,
-    Germplasm,
-    GermplasmInstitute,
-    GermplasmSet,
-    Institute,
-    Site
-} from './models/gnpis.model';
-
-describe('BrapiService', () => {
-
-    const location: BrapiLocation = {
-        locationDbId: '1',
-        locationName: 'loc1',
-        locationType: 'Collecting site',
-        abbreviation: null,
-        countryCode: 'Fr',
-        countryName: 'France',
-        instituteAddress: null,
-        instituteName: 'Insti',
-        altitude: null,
-        latitude: null,
-        longitude: null,
-    };
-
-    const contacts: BrapiContacts = {
-        contactDbId: 'c1',
-        name: 'contact1',
-        email: 'contact1@email.com',
-        type: 'contact',
-        institutionName: 'Inst',
-    };
-
-    const searchStudy: BrapiResult<BrapiStudy> = {
-        metadata: null,
-        result: {
-            studyDbId: 's1',
-            studyType: 'phenotype',
-            studyName: 'study1',
-            studyDescription: null,
-            seasons: ['winter', '2019'],
-            startDate: '2018',
-            endDate: null,
-            active: true,
-            programDbId: 'p1',
-            programName: 'program1',
-            trialDbIds: ['10', '20'],
-            location: location,
-            locationDbId: '1',
-            locationName: 'loc1',
-            contacts: [contacts],
-            additionalInfo: null,
-            dataLinks: []
-        }
-    };
-
-    const trial1: BrapiResult<BrapiTrial> = {
-        metadata: null,
-        result: {
-            trialDbId: '10',
-            trialName: 'trial_10',
-            trialType: 'project',
-            active: true,
-            studies: [
-                { studyDbId: 's1', studyName: 'study1' },
-                { studyDbId: 's2', studyName: 'study2' }
-            ]
-
-        }
-    };
-
-    const osbVariable: BrapiResults<BrapiObservationVariable> = {
-        metadata: null,
-        result: {
-            data: [{
-                observationVariableDbId: 'var1',
-                contextOfUse: null,
-                institution: 'Insti',
-                crop: 'WoodyPlant',
-                name: 'varaiable1',
-                ontologyDbId: 'WPO',
-                ontologyName: 'Woody Plant Ontology',
-                synonyms: ['First synonym'],
-                language: 'EN',
-                trait: {
-                    traitDbId: 't1',
-                    name: 'trait1',
-                    description: null,
-                },
-                documentationURL: null,
-            }]
-        }
-    };
-
-    const germplasm: BrapiResults<BrapiGermplasm> = {
-        metadata: null,
-        result: {
-            data: [{
-                germplasmDbId: 'g1',
-                accessionNumber: 'G_10',
-                defaultDisplayName: null,
-                germplasmPUI: null,
-                pedigree: null,
-                seedSource: null,
-                synonyms: null,
-                commonCropName: null,
-                instituteCode: null,
-                instituteName: null,
-                biologicalStatusOfAccessionCode: null,
-                countryOfOriginCode: null,
-                typeOfGermplasmStorageCode: null,
-                taxonIds: null,
-                germplasmName: 'germplam1',
-                genus: 'Populus',
-                species: 'x generosa',
-                subtaxa: '',
-                speciesAuthority: null,
-                subtaxaAuthority: null,
-                donors: null,
-                acquisitionDate: null
-            }, {
-                germplasmDbId: 'g2',
-                accessionNumber: 'G_20',
-                germplasmName: 'germplam2',
-                genus: 'Triticum',
-                species: 'aestivum',
-                subtaxa: 'subsp',
-                defaultDisplayName: null,
-                germplasmPUI: null,
-                pedigree: null,
-                seedSource: null,
-                synonyms: null,
-                commonCropName: null,
-                instituteCode: null,
-                instituteName: null,
-                biologicalStatusOfAccessionCode: null,
-                countryOfOriginCode: null,
-                typeOfGermplasmStorageCode: null,
-                taxonIds: null,
-                speciesAuthority: null,
-                subtaxaAuthority: null,
-                donors: null,
-                acquisitionDate: null
-            }],
-        }
-    };
-
-    const brapiSite: Site = {
-        latitude: null,
-        longitude: null,
-        siteId: null,
-        siteName: null,
-        siteType: null
-    };
-
-    const brapiSibling: BrapiSibling = {
-        germplasmDbId: 'frere1',
-        defaultDisplayName: 'frere1'
-    };
-
-    const brapiProgeny: BrapiProgeny = {
-        germplasmDbId: 'test',
-        defaultDisplayName: 'progeny1',
-        parentType: 'parent1'
-    };
-
-    const brapiGermplasmPedigree: BrapiResult<BrapiGermplasmPedigree> = {
-        metadata: null,
-        result: {
-            germplasmDbId: 'test',
-            defaultDisplayName: '12',
-            pedigree: null,
-            crossingPlan: null,
-            crossingYear: null,
-            familyCode: null,
-            parent1DbId: '11',
-            parent1Name: 'parent',
-            parent1Type: 'SELF',
-            parent2DbId: null,
-            parent2Name: null,
-            parent2Type: null,
-            siblings: [brapiSibling]
-        }
-    };
-
-    const brapiGermplasmProgeny: BrapiResult<BrapiGermplasmProgeny> = {
-        metadata: null,
-        result: {
-            germplasmDbId: 'test',
-            defaultDisplayName: '11',
-            progeny: [brapiProgeny]
-        }
-
-    };
-
-    const institute: Institute = {
-        instituteName: 'urgi',
-        instituteCode: 'inra',
-        acronym: 'urgi',
-        organisation: 'inra',
-        instituteType: 'labo',
-        webSite: 'www.labo.fr',
-        address: '12',
-        logo: null
-    };
-    const brapiInstitute: BrapiInstitute = {
-        instituteName: 'INRAE URGI',
-        instituteCode: '78000',
-        acronym: 'INRAE',
-        organisation: 'inrae',
-        instituteType: 'lab',
-        webSite: 'www.labo.fr',
-        instituteAddress: '18',
-        logo: null
-    };
-    const origin: GermplasmInstitute = {
-        ...institute,
-        institute: institute,
-        accessionNumber: '12',
-        accessionCreationDate: '1993',
-        materialType: 'feuille',
-        collectors: null,
-        registrationYear: '1996',
-        deregistrationYear: '1912',
-        distributionStatus: null
-    };
-
-    const collectingSite: BrapiCollectingSite = {
-        locationDbId: 'FR-78-INRAE',
-        locationName: 'Versailles',
-        coordinateUncertainty: null,
-        elevation: null,
-        georeferencingMethod: null,
-        latitudeDecimal: null,
-        latitudeDegrees: null,
-        locationDescription: null,
-        longitudeDecimal: null,
-        longitudeDegrees: null,
-        spatialReferenceSystem: null,
-    };
-
-    const brapiDonor: Donor = {
-        donorInstitute: institute,
-        donorGermplasmPUI: '12',
-        donorAccessionNumber: '12',
-        donorInstituteCode: 'urgi',
-        donationDate: null
-    };
-
-    const germplasmSet: GermplasmSet = {
-        germplasmCount: 12,
-        germplasmRef: null,
-        id: 12,
-        name: 'truc',
-        type: 'plan'
-    };
-
-    const brapiGermplasmAttributes: BrapiResult<BrapiGermplasmAttributes> = {
-        metadata: null,
-        result: {
-            germplasmDbId: 'test',
-            data: [{
-                attributeCode: 'att',
-                attributeDbId: 'attr2',
-                attributeName: 'longueur',
-                determinedDate: '2019',
-                value: '30'
-            }]
-        }
-    };
-
-    const germplasmTest: Germplasm = {
-        germplasmDbId: 'test',
-        defaultDisplayName: 'test',
-        accessionNumber: 'test',
-        germplasmName: 'test',
-        germplasmPUI: 'doi:1256',
-        pedigree: 'tree',
-        seedSource: 'inra',
-        synonyms: null,
-        commonCropName: null,
-        instituteCode: 'grc12',
-        instituteName: 'institut',
-        biologicalStatusOfAccessionCode: null,
-        countryOfOriginCode: null,
-        typeOfGermplasmStorageCode: null,
-        taxonIds: null,
-        genus: 'genre',
-        species: 'esp',
-        speciesAuthority: 'L',
-        subtaxa: null,
-        subtaxaAuthority: null,
-        donors: [brapiDonor],
-        acquisitionDate: null,
-        genusSpecies: null,
-        genusSpeciesSubtaxa: null,
-        taxonSynonyms: ['pomme', 'api'],
-        taxonCommonNames: ['pomme', 'api'],
-        taxonComment: null,
-        geneticNature: null,
-        comment: null,
-        photo: null,
-        holdingInstitute: institute,
-        holdingGenbank: institute,
-        presenceStatus: null,
-        children: null,
-        originSite: null,
-        collectingSite: null,
-        evaluationSites: null,
-        collector: origin,
-        breeder: origin,
-        distributors: [origin],
-        panel: [germplasmSet],
-        collection: [germplasmSet],
-        population: [germplasmSet],
-        'schema:includedInDataCatalog': null
-    };
-
-    const germplasmMcpdTest: BrapiGermplasmMcpd = {
-        groupId: '0',
-        accessionNames: ['test accession'],
-        accessionNumber: '01',
-        acquisitionDate: '2021',
-        acquisitionSourceCode: 'FR-urgi',
-        alternateIDs: ['Id1', 'Id2'],
-        ancestralData: null,
-        biologicalStatusOfAccessionCode: 'maintained',
-        breedingInstitutes: brapiInstitute,
-        collectingInfo: {
-            collectingDate: '2021',
-            collectingInstitutes: brapiInstitute,
-            collectingMissionIdentifier: '007',
-            collectingNumber: '3',
-            collectors: 'urgi',
-            materialType: 'germplasm',
-            collectingSite: collectingSite,
-        },
-        commonCropName: 'wheat',
-        countryOfOriginCode: 'FR',
-        donorInfo: {
-            donorAccessionNumber: 'ING007',
-            donorInstitute: brapiInstitute,
-            donationDate: '2021',
-        },
-        genus: 'Triti',
-        germplasmDbId: 'Fr-007',
-        germplasmPUI: 'urn/fr-007',
-        instituteCode: 'FR-INRAE',
-        mlsStatus: '0',
-        remarks: null,
-        safetyDuplicateInstitutes: null,
-        species: 'Triti',
-        speciesAuthority: null,
-        storageTypeCodes: null,
-        subtaxon: null,
-        subtaxonAuthority: null,
-        breederAccessionNumber: null,
-        breedingCreationYear: null,
-        catalogRegistrationYear: null,
-        catalogDeregistrationYear: null,
-        originLocationDbId: 'FR-Ver',
-        originLocationName: 'Versailles',
-        holdingInstitute: brapiInstitute,
-        holdingGenbank: brapiInstitute,
-        geneticNature: 'hybrid',
-        presenceStatus: null,
-        distributorInfos: null
-    };
-
-    const germplasmMcpdTestResult: BrapiResult<BrapiGermplasmMcpd> = {
-        metadata: null,
-        result: germplasmMcpdTest
-    };
-
-    let brapiService: BrapiService;
-    let http: HttpTestingController;
-
-    beforeEach(() => {
-        TestBed.configureTestingModule({
-            imports: [HttpClientTestingModule]
-        });
-        brapiService = TestBed.get(BrapiService);
-        http = TestBed.get(HttpTestingController);
-    });
-
-    afterEach(() => http.verify());
-
-    it('should fetch the study with data source', () => {
-        let fetchedStudy: BrapiResult<BrapiStudy>;
-        const studyDbId: string = searchStudy.result.studyDbId;
-        brapiService.study(searchStudy.result.studyDbId).subscribe(response => {
-            fetchedStudy = response;
-        });
-        http.expectOne(`brapi/v1/studies/${studyDbId}`)
-            .flush(searchStudy);
-
-        expect(fetchedStudy).toEqual(searchStudy);
-    });
-
-    it('should fetch the germplasm of studies call', () => {
-
-        let fetchedGermplasm: BrapiResults<BrapiGermplasm>;
-        const studyDbId: string = searchStudy.result.studyDbId;
-        brapiService.studyGermplasms(searchStudy.result.studyDbId).subscribe(response => {
-            fetchedGermplasm = response;
-        });
-        http.expectOne(`brapi/v1/studies/${studyDbId}/germplasm`)
-            .flush(germplasm);
-
-        expect(fetchedGermplasm).toEqual(germplasm);
-
-    });
-
-    it('should fetch the variables', () => {
-
-        let fetchedVariables: BrapiResults<BrapiObservationVariable>;
-        const studyDbId: string = searchStudy.result.studyDbId;
-        brapiService.studyObservationVariables(searchStudy.result.studyDbId).subscribe(response => {
-            fetchedVariables = response;
-        });
-        http.expectOne(`brapi/v1/studies/${studyDbId}/observationVariables`)
-            .flush(osbVariable);
-
-        expect(fetchedVariables).toEqual(osbVariable);
-
-    });
-
-    it('should fetch the trials', () => {
-
-        let fetchedTrials: BrapiResult<BrapiTrial>;
-        const trialDbId: string = trial1.result.trialDbId;
-        brapiService.studyTrials(trialDbId).subscribe(response => {
-            fetchedTrials = response;
-        });
-        http.expectOne(`brapi/v1/trials/${trialDbId}`)
-            .flush(trial1);
-
-        expect(fetchedTrials).toEqual(trial1);
-
-    });
-
-    it('should fetch location with data source', () => {
-        const mockResponse: BrapiResult<BrapiLocation> = {
-            metadata: null,
-            result: location
-        };
-        let actualLocation: BrapiLocation;
-        const locationId = mockResponse.result.locationDbId;
-        brapiService.location(mockResponse.result.locationDbId).subscribe(response => actualLocation = response.result);
-
-        http.expectOne(`brapi/v1/locations/${locationId}`)
-            .flush(mockResponse);
-
-        expect(actualLocation).toEqual(location);
-    });
-
-    it('should fetch the pedigree', () => {
-
-        let fetchedGermplasmPedigree: BrapiResult<BrapiGermplasmPedigree>;
-        const germplasmDbId: string = brapiGermplasmPedigree.result.germplasmDbId;
-        brapiService.germplasmPedigree(germplasmDbId).subscribe(response => {
-            fetchedGermplasmPedigree = response;
-        });
-        http.expectOne(`brapi/v1/germplasm/${germplasmDbId}/pedigree`)
-            .flush(brapiGermplasmPedigree);
-
-        expect(fetchedGermplasmPedigree).toEqual(brapiGermplasmPedigree);
-
-    });
-
-    // TODO test the progeny call when the information about parent will be added
-    /*it('should fetch the germplasm progeny', () => {
-
-        let fetchedGermplasmProgeny: GermplasmResult<BrapiGermplasmProgeny>;
-        const germplasmDbId: string = brapiGermplasmProgeny.result.germplasmDbId;
-        brapiService.germplasmProgeny(germplasmDbId).subscribe(response => {
-            fetchedGermplasmProgeny = response;
-        });
-        http.expectOne(`brapi/v1/germplasm/${germplasmDbId}/progeny`)
-            .flush(brapiGermplasmProgeny);
-
-        expect(fetchedGermplasmProgeny).toEqual(brapiGermplasmProgeny);
-
-    });*/
-
-    it('should fetch the germplasm attributes', () => {
-
-        let fetchedGermplasmAttributes: BrapiResult<BrapiGermplasmAttributes>;
-        const germplasmDbId: string = germplasmTest.germplasmDbId;
-        brapiService.germplasmAttributes(germplasmDbId).subscribe(response => {
-            fetchedGermplasmAttributes = response;
-        });
-        http.expectOne(`brapi/v1/germplasm/${germplasmDbId}/attributes`)
-            .flush(brapiGermplasmAttributes);
-
-        expect(fetchedGermplasmAttributes).toEqual(brapiGermplasmAttributes);
-
-    });
-
-    it('should fetch the germplasm mcpd', () => {
-
-        let fetchedGermplasmMcpd: BrapiResult<BrapiGermplasmMcpd>;
-        const germplasmDbId: string = germplasmTest.germplasmDbId;
-        brapiService.germplasmMcpd(germplasmDbId).subscribe(response => {
-            fetchedGermplasmMcpd = response;
-        });
-        http.expectOne(`brapi/v1/germplasm/${germplasmDbId}/mcpd`)
-            .flush(germplasmMcpdTestResult);
-
-        expect(fetchedGermplasmMcpd).toEqual(germplasmMcpdTestResult);
-
-    });
-
-});
diff --git a/frontend/src/app/brapi.service.ts b/frontend/src/app/brapi.service.ts
deleted file mode 100644
index aca2463a41295b6b0d303e164733b13d5f96ab02..0000000000000000000000000000000000000000
--- a/frontend/src/app/brapi.service.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs';
-import { HttpClient } from '@angular/common/http';
-import {
-    BrapiGermplasm,
-    BrapiGermplasmAttributes,
-    BrapiGermplasmMcpd,
-    BrapiGermplasmPedigree,
-    BrapiLocation,
-    BrapiObservationVariable,
-    BrapiResult,
-    BrapiResults,
-    BrapiStudy,
-    BrapiTrial
-} from './models/brapi.model';
-
-
-export const BASE_URL = 'brapi/v1';
-
-@Injectable({
-    providedIn: 'root'
-})
-export class BrapiService {
-
-    constructor(private http: HttpClient) {
-    }
-
-    germplasmPedigree(germplasmDbId: string): Observable<BrapiResult<BrapiGermplasmPedigree>> {
-        return this.http
-            .get<BrapiResult<BrapiGermplasmPedigree>>(`${BASE_URL}/germplasm/${germplasmDbId}/pedigree`);
-    }
-
-    // TODO use the progeny call when the information about parent will be added
-    /* germplasmProgeny(germplasmDbId: string): Observable<GermplasmResult<BrapiGermplasmProgeny>> {
-        return this.http.get<GermplasmResult<BrapiGermplasmProgeny>>(`${BASE_URL}/germplasm/${germplasmDbId}/progeny`);
-    } */
-
-    germplasmAttributes(germplasmDbId: string): Observable<BrapiResult<BrapiGermplasmAttributes>> {
-        return this.http
-            .get<BrapiResult<BrapiGermplasmAttributes>>(`${BASE_URL}/germplasm/${germplasmDbId}/attributes`);
-    }
-
-    study(studyDbId: string): Observable<BrapiResult<BrapiStudy>> {
-        return this.getWithSource(`${BASE_URL}/studies/${studyDbId}`);
-    }
-
-    studyGermplasms(studyDbId: string): Observable<BrapiResults<BrapiGermplasm>> {
-        return this.http
-            .get<BrapiResults<BrapiGermplasm>>(`${BASE_URL}/studies/${studyDbId}/germplasm`);
-    }
-
-    studyObservationVariables(studyDbId: string): Observable<BrapiResults<BrapiObservationVariable>> {
-        return this.http
-            .get<BrapiResults<BrapiObservationVariable>>(`${BASE_URL}/studies/${studyDbId}/observationVariables`);
-    }
-
-    location(locationId: string): Observable<BrapiResult<BrapiLocation>> {
-        return this.getWithSource(`${BASE_URL}/locations/${locationId}`);
-    }
-
-    studyTrials(trialsId: string): Observable<BrapiResult<BrapiTrial>> {
-        return this.http
-            .get<BrapiResult<BrapiTrial>>(`${BASE_URL}/trials/${trialsId}`);
-    }
-    germplasmMcpd(germplasmDbId: string): Observable<BrapiResult<BrapiGermplasmMcpd>> {
-        return this.http
-            .get<BrapiResult<BrapiGermplasmMcpd>>(`${BASE_URL}/germplasm/${germplasmDbId}/mcpd`);
-    }
-
-
-    /**
-     * Get BrAPI single result response and replace the 'schema:includedInDataCatalog' URI value to the actual source object value.
-     */
-    private getWithSource<T>(url: string): Observable<BrapiResult<T>> {
-        return this.http.get<BrapiResult<T>>(
-            url,
-            // Ask JSON-LD (or JSON) response
-            { headers: { 'Accept': 'application/ld+json,application/json' } }
-        );
-    }
-}
diff --git a/frontend/src/app/card-generic-document/card-generic-document.component.html b/frontend/src/app/card-generic-document/card-generic-document.component.html
deleted file mode 100644
index 369f47c6994b4f6dd02e32b0d056b4bad11f233c..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-generic-document/card-generic-document.component.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!--
-
-TODO: display generic document name and identifier here?
--->
-
-
-<!-- Document PUI -->
-<faidare-card-row
-  class="pui-row"
-  label="Permanent unique identifier"
-  [test]="document['@id'] && !document['@id'].startsWith('urn:')"
-  [value]="document['@id']">
-</faidare-card-row>
-
-
-<ng-container *ngIf="dataSource && dataSource['schema:name']">
-
-  <faidare-card-row
-    label="Source"
-    class="data-source-row"
-    [test]="dataSource['schema:url']">
-    <ng-template>
-      <!-- Data source URL link -->
-      <a target="_blank"
-         [href]="dataSource['schema:url']">
-
-        <!-- Data source logo -->
-        <img *ngIf="dataSource['schema:image']"
-             [src]="dataSource['schema:image']"
-             alt="{{ dataSource['schema:name'] }} logo"
-             style="max-height: 60px;"/>
-
-        <!-- Data source link -->
-        <!-- {{ dataSource['schema:name'] }}-->
-      </a>
-    </ng-template>
-  </faidare-card-row>
-
-  <faidare-card-row
-    label="Data link"
-    class="data-link-row"
-    [test]="document['schema:url']">
-    <ng-template>
-      <!-- Document URL link  on data source web site -->
-      <a target="_blank" [href]="document['schema:url']">
-        Link to this {{ documentType }} on {{ dataSource["schema:name"] }}
-      </a>
-    </ng-template>
-  </faidare-card-row>
-
-</ng-container>
diff --git a/frontend/src/app/card-generic-document/card-generic-document.component.spec.ts b/frontend/src/app/card-generic-document/card-generic-document.component.spec.ts
deleted file mode 100644
index ce782db6f635e8ac0c450d8529c4c1b76062dd06..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-generic-document/card-generic-document.component.spec.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { CardGenericDocumentComponent } from './card-generic-document.component';
-import { ComponentTester, speculoosMatchers } from 'ngx-speculoos';
-import { DataDiscoverySource } from '../models/data-discovery.model';
-import { CardRowComponent } from '../card-row/card-row.component';
-import { GnpisService } from '../gnpis.service';
-import { of } from 'rxjs/internal/observable/of';
-
-
-class CardGenericDocumentComponentTester extends ComponentTester<CardGenericDocumentComponent> {
-    constructor() {
-        super(CardGenericDocumentComponent);
-    }
-
-    get pui() {
-        return this.element('.pui-row .value');
-    }
-
-    get dataSource() {
-        return this.element('.data-source-row a');
-    }
-
-    get dataLink() {
-        return this.element('.data-link-row a');
-    }
-}
-
-describe('CardGenericDocumentComponent', () => {
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    const dataSource: DataDiscoverySource = {
-        '@id': 'urn:source',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'Example source',
-        'schema:url': 'http://example.com',
-        'schema:image': 'http://example.com/logo.png'
-    };
-
-    beforeEach(async () => {
-        const gnpisService = jasmine.createSpyObj(
-            'GnpisService', [
-                'getSource'
-            ]
-        );
-        gnpisService.getSource.and.returnValue(of(dataSource));
-
-        await TestBed.configureTestingModule({
-            declarations: [CardRowComponent, CardGenericDocumentComponent],
-            providers: [
-                { provide: GnpisService, useValue: gnpisService }
-            ]
-        }).compileComponents();
-    });
-
-    it('should hide URN PUI', async(() => {
-        const tester = new CardGenericDocumentComponentTester();
-        tester.componentInstance.document = {
-            '@id': 'urn:foo/bar'
-        };
-        tester.detectChanges();
-
-        expect(tester.pui).toBeFalsy();
-    }));
-
-    it('should show non-URN PUI', async(() => {
-        const tester = new CardGenericDocumentComponentTester();
-        const document = {
-            '@id': 'https://doi.org/....'
-        };
-        tester.componentInstance.document = document;
-        tester.detectChanges();
-        expect(tester.pui).toContainText(document['@id']);
-    }));
-
-
-    it('should hide data source', async(() => {
-        const tester = new CardGenericDocumentComponentTester();
-        tester.componentInstance.document = {
-            'schema:includedInDataCatalog': dataSource['@id']
-        };
-        tester.detectChanges();
-
-        expect(tester.componentInstance.dataSource).toBe(dataSource);
-    }));
-
-
-    it('should hide no data link', async(() => {
-        const tester = new CardGenericDocumentComponentTester();
-        tester.componentInstance.document = {
-            'schema:includedInDataCatalog': dataSource['@id'],
-            'schema:url': null
-        };
-        tester.detectChanges();
-
-        expect(tester.componentInstance.dataSource).toBe(dataSource);
-        expect(tester.dataLink).toBeFalsy();
-    }));
-
-
-    it('should show data link', async(() => {
-        const tester = new CardGenericDocumentComponentTester();
-        tester.componentInstance.document = {
-            'schema:includedInDataCatalog': dataSource['@id'],
-            'schema:url': 'http://example.com/...'
-        };
-        tester.detectChanges();
-
-        expect(tester.componentInstance.dataSource).toBe(dataSource);
-        expect(tester.dataLink).toBeTruthy();
-        expect(tester.dataLink.attr('href')).toEqual(tester.componentInstance.document['schema:url']);
-    }));
-});
diff --git a/frontend/src/app/card-generic-document/card-generic-document.component.ts b/frontend/src/app/card-generic-document/card-generic-document.component.ts
deleted file mode 100644
index b123303735c01e620c0ce2dd9964929b42b88f68..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-generic-document/card-generic-document.component.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import * as schema from '../models/schema.org.model';
-import { GnpisService } from '../gnpis.service';
-
-@Component({
-    selector: 'faidare-card-generic-document',
-    templateUrl: './card-generic-document.component.html'
-})
-export class CardGenericDocumentComponent implements OnInit {
-
-    @Input() document: schema.Dataset;
-    @Input() documentType: string;
-
-    dataSource: schema.DataCatalog;
-
-    constructor(private gnpisService: GnpisService) {
-    }
-
-    ngOnInit() {
-        let sourceURI = this.document['schema:includedInDataCatalog'];
-
-        // TODO: Make sure this never happen in ETL (always fill this field)
-        if (typeof sourceURI !== 'string') {
-            sourceURI = GnpisService.URGI_SOURCE_URI;
-        }
-
-        this.gnpisService.getSource(sourceURI).subscribe(dataSource => {
-            this.dataSource = dataSource;
-        });
-    }
-
-}
diff --git a/frontend/src/app/card-row/card-row.component.html b/frontend/src/app/card-row/card-row.component.html
deleted file mode 100644
index 792b334789ec5dad71c4f66fe0665cc811537504..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-row/card-row.component.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<ng-container *ngIf="shouldShow()">
-  <div class="row row-sep">
-    <div class="col-4 field my-2">
-      {{ label }}
-    </div>
-    <div class="col value my-2">
-      <ng-template #includeTemplate [ngTemplateOutlet]="template"></ng-template>
-      <ng-template #includeStringValue>
-        {{ value }}
-      </ng-template>
-      <ng-container *ngIf="value; then includeStringValue else includeTemplate"></ng-container>
-    </div>
-  </div>
-</ng-container>
diff --git a/frontend/src/app/card-row/card-row.component.scss b/frontend/src/app/card-row/card-row.component.scss
deleted file mode 100644
index d5fab77cbcf99eb6409d67cec2b3906bb40d8186..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-row/card-row.component.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-@import '../../styles.scss';
-
-.field {
-  font-weight: bold;
-  overflow-wrap: normal;
-}
-
diff --git a/frontend/src/app/card-row/card-row.component.spec.ts b/frontend/src/app/card-row/card-row.component.spec.ts
deleted file mode 100644
index ad3be6597903c166e1c3ea2ffb17f98601b3e1cd..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-row/card-row.component.spec.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { CardRowComponent } from './card-row.component';
-import { ComponentTester, speculoosMatchers } from 'ngx-speculoos';
-import { Component, ViewChild } from '@angular/core';
-
-class CardRowComponentTester extends ComponentTester<CardRowComponent> {
-    constructor() {
-        super(CardRowComponent);
-    }
-
-    get rowDiv() {
-        return this.element('div.row');
-    }
-
-    get labelDiv() {
-        return this.element('div.field');
-    }
-
-    get valueDiv() {
-        return this.element('div.value');
-    }
-}
-
-
-/**
- * Test faidare-card-row with a provided `ng-template`
- */
-@Component({
-    selector: 'faidare-test',
-    template: `
-        <faidare-card-row>
-            <ng-template>
-                <strong>Value HTML template</strong>
-            </ng-template>
-        </faidare-card-row>`
-})
-class CardRowWithTemplateComponent {
-    @ViewChild(CardRowComponent) component: CardRowComponent;
-}
-
-describe('CardRowComponent', () => {
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    beforeEach(async(() =>
-        TestBed.configureTestingModule({
-            declarations: [CardRowComponent, CardRowWithTemplateComponent]
-        }).compileComponents()
-    ));
-
-
-    it('should hide falsy value', () => {
-        const tester = new CardRowComponentTester();
-        tester.componentInstance.label = 'Label1';
-        tester.componentInstance.value = null;
-        tester.detectChanges();
-
-        expect(tester.rowDiv).toBeFalsy();
-    });
-
-    it('should show truthy value', () => {
-        const tester = new CardRowComponentTester();
-        tester.componentInstance.label = 'Label1';
-        tester.componentInstance.value = 'Value1';
-        tester.detectChanges();
-
-        expect(tester.rowDiv).toBeTruthy();
-        expect(tester.labelDiv).toContainText(tester.componentInstance.label);
-        expect(tester.valueDiv).toContainText(tester.componentInstance.value);
-    });
-
-    it('should hide falsy test', () => {
-        const tester = new CardRowComponentTester();
-        tester.componentInstance.label = 'Label1';
-        tester.componentInstance.value = 'Value1';
-        tester.componentInstance.test = false;
-        tester.detectChanges();
-
-        expect(tester.rowDiv).toBeFalsy();
-    });
-
-    it('should hide truthy test, falsy value', () => {
-        const tester = new CardRowComponentTester();
-        tester.componentInstance.label = 'Label1';
-        tester.componentInstance.value = '';
-        tester.componentInstance.test = true;
-        tester.detectChanges();
-
-        expect(tester.rowDiv).toBeFalsy();
-    });
-
-    it('should show truthy test, truthy value', () => {
-        const tester = new CardRowComponentTester();
-        tester.componentInstance.label = 'Label1';
-        tester.componentInstance.value = 'Value1';
-        tester.componentInstance.test = true;
-        tester.detectChanges();
-
-        expect(tester.rowDiv).toBeTruthy();
-        expect(tester.labelDiv).toContainText(tester.componentInstance.label);
-        expect(tester.valueDiv).toContainText(tester.componentInstance.value);
-    });
-
-
-    it('should hide falsy test, provided template', async(() => {
-        const fixture = TestBed.createComponent(CardRowWithTemplateComponent);
-        fixture.componentInstance.component.label = 'Label1';
-        fixture.componentInstance.component.test = '';
-        fixture.detectChanges();
-
-        const element: HTMLElement = fixture.nativeElement;
-        expect(element.querySelector('div.row')).toBeFalsy();
-    }));
-
-
-    it('should show truthy test, provided template', async(() => {
-        const fixture = TestBed.createComponent(CardRowWithTemplateComponent);
-        const component = fixture.componentInstance.component;
-        component.label = 'Label2';
-        component.test = true;
-        fixture.detectChanges();
-
-        const element: HTMLElement = fixture.nativeElement;
-        expect(element.querySelector('div.row')).toBeTruthy();
-        expect(element.querySelector('div.field').textContent).toContain(component.label);
-        expect(element.querySelector('div.col').textContent).toContain('Value HTML template');
-    }));
-});
diff --git a/frontend/src/app/card-row/card-row.component.ts b/frontend/src/app/card-row/card-row.component.ts
deleted file mode 100644
index 639a4defdcec9f96b951043da42cfbb971d4b3c4..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-row/card-row.component.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
-
-@Component({
-    selector: 'faidare-card-row',
-    templateUrl: './card-row.component.html',
-    styleUrls: ['./card-row.component.scss']
-})
-export class CardRowComponent {
-
-    @Input() label: string;
-    @Input() test: any = true;
-    @Input() value: string;
-
-    @ContentChild(TemplateRef) template: TemplateRef<any>;
-
-    shouldShow(): boolean {
-        return this.test && (
-            // Value not provided and template provided
-            (this.value === undefined && this.template !== undefined)
-            ||
-            // Or value truthy
-            !!this.value
-        );
-    }
-}
diff --git a/frontend/src/app/card-section/card-section.component.html b/frontend/src/app/card-section/card-section.component.html
deleted file mode 100644
index bcf4fd14571926df10dfd812722441942d0c646c..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-section/card-section.component.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<div class="card mb-3" *ngIf="test">
-  <div class="card-header">
-    {{ header }}
-  </div>
-  <ng-container [ngTemplateOutlet]="template"></ng-container>
-</div>
diff --git a/frontend/src/app/card-section/card-section.component.scss b/frontend/src/app/card-section/card-section.component.scss
deleted file mode 100644
index 78b6d191061a3269423b24f33facc74d9a1b2343..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-section/card-section.component.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-@import '../../styles.scss';
-
-a {
-  text-decoration: underline;
-}
-
-.card {
-  border: none;
-}
-
-.card-header {
-  font-size: large;
-  font-weight: bold;
-  color: #f5f5f5;
-  background-image:repeating-linear-gradient(#0f96cd, #0f6191, #0f76a5) ;
-}
-
diff --git a/frontend/src/app/card-section/card-section.component.spec.ts b/frontend/src/app/card-section/card-section.component.spec.ts
deleted file mode 100644
index 72933da510e874fec9e78f83434c3b8a16080e76..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-section/card-section.component.spec.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { CardSectionComponent } from './card-section.component';
-import { speculoosMatchers } from 'ngx-speculoos';
-import { Component, ViewChild } from '@angular/core';
-
-
-/**
- * Test faidare-card-section with a provided `ng-template`
- */
-@Component({
-    selector: 'faidare-test',
-    template: `
-        <faidare-card-section>
-            <ng-template>
-                <div class="test-body">Body HTML template</div>
-            </ng-template>
-        </faidare-card-section>`
-})
-class CardSectionTestWrapperComponent {
-    @ViewChild(CardSectionComponent) component: CardSectionComponent;
-}
-
-describe('CardSectionComponent', () => {
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    beforeEach(async(() =>
-        TestBed.configureTestingModule({
-            declarations: [CardSectionComponent, CardSectionTestWrapperComponent]
-        }).compileComponents()
-    ));
-
-    it('should hide falsy test', async(() => {
-        const fixture = TestBed.createComponent(CardSectionTestWrapperComponent);
-        const component = fixture.componentInstance.component;
-        component.header = 'Header1';
-        component.test = '';
-        fixture.detectChanges();
-
-        const element: HTMLElement = fixture.nativeElement;
-        const cardDiv = element.querySelector('div.card');
-        expect(cardDiv).toBeFalsy();
-    }));
-
-
-    it('should show truthy test', async(() => {
-        const fixture = TestBed.createComponent(CardSectionTestWrapperComponent);
-        const component = fixture.componentInstance.component;
-        component.header = 'Header2';
-        component.test = true;
-        fixture.detectChanges();
-
-        const element: HTMLElement = fixture.nativeElement;
-        const cardDiv = element.querySelector('div.card');
-        const headerDiv = element.querySelector('div.card-header');
-        const bodyDiv = element.querySelector('div.test-body');
-        expect(cardDiv).toBeTruthy();
-        expect(headerDiv.textContent).toContain(component.header);
-        expect(bodyDiv.textContent).toContain('Body HTML template');
-    }));
-});
diff --git a/frontend/src/app/card-section/card-section.component.ts b/frontend/src/app/card-section/card-section.component.ts
deleted file mode 100644
index b4388cd83467b1d892f6ddc4ebf235cf3f1d52d8..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-section/card-section.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
-
-@Component({
-    selector: 'faidare-card-section',
-    templateUrl: './card-section.component.html',
-    styleUrls: ['./card-section.component.scss']
-})
-export class CardSectionComponent {
-
-    @Input() header: string;
-    @Input() test: any = true;
-
-    @ContentChild(TemplateRef) template: TemplateRef<any>;
-
-}
diff --git a/frontend/src/app/card-table/card-table.component.html b/frontend/src/app/card-table/card-table.component.html
deleted file mode 100644
index fff69973e8fd7824626bd52051daa317c30d34cb..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-table/card-table.component.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<div class="card">
-  <table class="table table-sm table-striped">
-    <thead *ngIf="headers">
-    <tr>
-      <th *ngFor="let header of headers" scope="col">
-        {{ header }}
-      </th>
-    </tr>
-    </thead>
-    <tbody>
-    <ng-container *ngFor="let row of rows"
-                  [ngTemplateOutlet]="template"
-                  [ngTemplateOutletContext]="{$implicit: row}">
-    </ng-container>
-    </tbody>
-  </table>
-</div>
diff --git a/frontend/src/app/card-table/card-table.component.scss b/frontend/src/app/card-table/card-table.component.scss
deleted file mode 100644
index bcf9e14865592cb709153a19dc4cb76adf6e7902..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-table/card-table.component.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-
-thead th {
-  position: sticky;
-  top: 0;
-  background-color: white;
-}
-
diff --git a/frontend/src/app/card-table/card-table.component.spec.ts b/frontend/src/app/card-table/card-table.component.spec.ts
deleted file mode 100644
index 74671515ea31da18d333c2423ea91aa59aaee9ac..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-table/card-table.component.spec.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { CardTableComponent } from './card-table.component';
-import { Component, ViewChild } from '@angular/core';
-
-/**
- * Test faidare-card-table with a simple provided row `ng-template`
- */
-@Component({
-    selector: 'faidare-test',
-    template: `
-        <faidare-card-table>
-            <ng-template let-row>
-                <tr>
-                    <td>{{ row[0] }}</td>
-                    <td>{{ row[1] }}</td>
-                    <td>{{ row[2] }}</td>
-                </tr>
-            </ng-template>
-        </faidare-card-table>`
-})
-class CardTableTestWrapperComponent {
-    @ViewChild(CardTableComponent) component: CardTableComponent;
-}
-
-describe('CardTableComponent', () => {
-
-    beforeEach(async(() =>
-        TestBed.configureTestingModule({
-            declarations: [CardTableComponent, CardTableTestWrapperComponent]
-        }).compileComponents()
-    ));
-
-    const headers = [
-        'h1', 'h2', 'h3'
-    ];
-    const rows = [
-        ['a', 'b', 'c'],
-        ['d', 'e', 'f'],
-        ['g', 'h', 'i'],
-    ];
-
-    it('should hide headers and show rows', () => {
-        const fixture = TestBed.createComponent(CardTableTestWrapperComponent);
-        const component = fixture.componentInstance.component;
-        component.headers = null;
-        component.rows = rows;
-        fixture.detectChanges();
-
-        const element: HTMLElement = fixture.nativeElement;
-        const thead = element.querySelector('thead');
-        expect(thead).toBeFalsy();
-
-        const tds = element.querySelectorAll('td');
-        expect(tds.length).toBe(9);
-        expect(tds[0].textContent).toContain(rows[0][0]);
-        expect(tds[5].textContent).toContain(rows[1][2]);
-    });
-
-    it('should show headers and rows', () => {
-        const fixture = TestBed.createComponent(CardTableTestWrapperComponent);
-        const component = fixture.componentInstance.component;
-        component.headers = headers;
-        component.rows = rows;
-        fixture.detectChanges();
-
-        const element: HTMLElement = fixture.nativeElement;
-        const ths = element.querySelectorAll('thead th');
-        expect(ths.length).toBe(3);
-        expect(ths[0].textContent).toContain(headers[0]);
-        expect(ths[2].textContent).toContain(headers[2]);
-
-        const tds = element.querySelectorAll('td');
-        expect(tds.length).toBe(9);
-        expect(tds[0].textContent).toContain(rows[0][0]);
-        expect(tds[5].textContent).toContain(rows[1][2]);
-    });
-});
diff --git a/frontend/src/app/card-table/card-table.component.ts b/frontend/src/app/card-table/card-table.component.ts
deleted file mode 100644
index 7d079c135256a83c9c5f77017d1683b2444ea0cd..0000000000000000000000000000000000000000
--- a/frontend/src/app/card-table/card-table.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
-
-@Component({
-    selector: 'faidare-card-table',
-    templateUrl: './card-table.component.html',
-    styleUrls: ['./card-table.component.scss']
-})
-export class CardTableComponent {
-
-    @Input() headers: string[];
-    @Input() rows: any[];
-
-    @ContentChild(TemplateRef) template: TemplateRef<any>;
-
-}
diff --git a/frontend/src/app/error-interceptor.service.spec.ts b/frontend/src/app/error-interceptor.service.spec.ts
deleted file mode 100644
index 5b321dff20ab54e1394e59d97eee166e14415d03..0000000000000000000000000000000000000000
--- a/frontend/src/app/error-interceptor.service.spec.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-
-import { ErrorInterceptorService, HttpError } from './error-interceptor.service';
-import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
-import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
-
-describe('ErrorInterceptorService', () => {
-    let service: ErrorInterceptorService;
-    let http: HttpTestingController;
-    let httpClient: HttpClient;
-    const noop = () => {
-    };
-
-    beforeEach(() => {
-        TestBed.configureTestingModule({
-            imports: [HttpClientTestingModule],
-            providers: [
-                {
-                    provide: HTTP_INTERCEPTORS,
-                    useExisting: ErrorInterceptorService,
-                    multi: true
-                }
-            ]
-        });
-
-        service = TestBed.get(ErrorInterceptorService);
-        http = TestBed.get(HttpTestingController);
-        httpClient = TestBed.get(HttpClient);
-    });
-
-    it('should emit error when error is not an HTTP response', () => {
-        let error: HttpError;
-        service.getErrors().subscribe(err => {
-            error = err;
-        });
-
-        httpClient.get('/test').subscribe({ next: null, error: noop });
-        http.expectOne('/test').error(new ErrorEvent('unknown', { message: 'not good' }));
-
-        expect(error.status).toBeNull();
-        expect(error.message).toBe('not good');
-    });
-
-    it('should emit error when error is an HTTP response', () => {
-        let error: HttpError;
-        service.getErrors().subscribe(err => {
-            error = err;
-        });
-
-        httpClient.get('/test').subscribe({ next: null, error: noop });
-        http.expectOne('/test').flush(null, { status: 500, statusText: 'Server Error' });
-
-        expect(error.status).toBe(500);
-        expect(error.message).toBe('Http failure response for /test: 500 Server Error');
-    });
-
-    it('should emit error when error is a BrAPI error response', () => {
-        let error: HttpError;
-        service.getErrors().subscribe(err => {
-            error = err;
-        });
-
-        const result = {
-            metadata: {
-                status: [{
-                    name: 'BrAPI server error description'
-                }]
-            }
-        };
-
-        httpClient.get('/test').subscribe({ next: null, error: noop });
-        http.expectOne('/test').flush(result, { status: 500, statusText: 'Server Error' });
-
-        expect(error.status).toBe(500);
-        expect(error.message).toBe(result.metadata.status[0].name);
-    });
-
-    it('should emit error when error is a BrAPI error response with multiple errors', () => {
-        let error: HttpError;
-        service.getErrors().subscribe(err => {
-            error = err;
-        });
-
-        const result = {
-            metadata: {
-                status: [{
-                    name: 'error 1'
-                }, {
-                    name: 'error 2'
-                }]
-            }
-        };
-
-        httpClient.get('/test').subscribe({ next: null, error: noop });
-        http.expectOne('/test').flush(result, { status: 500, statusText: 'Server Error' });
-
-        expect(error.status).toBe(500);
-        expect(error.message).toBe('error 1; error 2');
-    });
-});
diff --git a/frontend/src/app/error-interceptor.service.ts b/frontend/src/app/error-interceptor.service.ts
deleted file mode 100644
index f969531ca35aba7e6599874ab39cf7f7b22e9184..0000000000000000000000000000000000000000
--- a/frontend/src/app/error-interceptor.service.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { Injectable } from '@angular/core';
-import {
-    HttpErrorResponse,
-    HttpEvent,
-    HttpHandler,
-    HttpInterceptor,
-    HttpRequest
-} from '@angular/common/http';
-import { Observable, Subject } from 'rxjs';
-import { tap } from 'rxjs/operators';
-
-export interface HttpError {
-    status: number | null;
-    message: string;
-}
-
-@Injectable({
-    providedIn: 'root'
-})
-export class ErrorInterceptorService implements HttpInterceptor {
-
-    private errorSubject = new Subject<HttpError>();
-
-    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
-        return next.handle(req).pipe(
-            tap(() => null, err => this.errorSubject.next(this.toError(err)))
-        );
-    }
-
-    private toError(errorResponse: HttpErrorResponse) {
-        const errorBody = errorResponse.error;
-        if (errorBody instanceof ErrorEvent) {
-            // A client-side or network error occurred.
-            return {
-                status: null,
-                message: errorBody.message
-            };
-        } else {
-            // The backend returned an unsuccessful response code.
-            let message = errorResponse.message;
-            if (errorBody && errorBody.metadata && errorBody.metadata.status) {
-                message = errorBody.metadata.status.map(status => status.name).join('; ');
-            }
-            return {
-                status: errorResponse.status,
-                message
-            };
-        }
-    }
-
-    getErrors(): Observable<HttpError> {
-        return this.errorSubject.asObservable();
-    }
-
-}
diff --git a/frontend/src/app/error/error.component.html b/frontend/src/app/error/error.component.html
deleted file mode 100644
index f5ffeccf89d08f3ffb8d730b16350b5f436ddd65..0000000000000000000000000000000000000000
--- a/frontend/src/app/error/error.component.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<div class="error alert alert-warning" *ngIf="error$ | async as error">
-  <div class="d-flex">
-    <div class="mr-3" style="font-size: 3em;">
-      <span class="fa fa-frown-o"></span>
-    </div>
-    <div>
-      <p>
-        An unexpected error occurred.<br/>
-        <a href="javascript:window.location.reload(true)">Refresh the page</a>
-        <ng-container *ngIf="canGoBack()">
-          , <a (click)="goBack();$event.preventDefault()" href="#">go back to the last page</a>
-        </ng-container>
-        or retry later.
-      </p>
-      <p>
-        Please contact <a href="mailto:urgi-support@inra.fr">urgi-support@inra.fr</a> if the problem persists.
-      </p>
-      <code *ngIf="error.status || error.message">
-        <span *ngIf="error.status" id="error-status">
-          Status: {{ error.status }}
-        </span>
-        <span *ngIf="error.message" id="error-message">
-          <br/>
-          Message: {{ error.message }}
-        </span>
-      </code>
-    </div>
-  </div>
-</div>
diff --git a/frontend/src/app/error/error.component.scss b/frontend/src/app/error/error.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/frontend/src/app/error/error.component.spec.ts b/frontend/src/app/error/error.component.spec.ts
deleted file mode 100644
index d6debb1a529c7cb402eae8cabf6d5fa84c8a7b95..0000000000000000000000000000000000000000
--- a/frontend/src/app/error/error.component.spec.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-import { NavigationEnd, NavigationStart, Router, RouterEvent } from '@angular/router';
-import { HttpClientTestingModule } from '@angular/common/http/testing';
-import { Subject } from 'rxjs';
-import { ComponentTester, speculoosMatchers } from 'ngx-speculoos';
-
-import { Location } from '@angular/common';
-import { ErrorComponent } from './error.component';
-import { ErrorInterceptorService, HttpError } from '../error-interceptor.service';
-
-class ErrorComponentTester extends ComponentTester<ErrorComponent> {
-    constructor() {
-        super(ErrorComponent);
-    }
-
-    get error() {
-        return this.element('.error');
-    }
-
-    get status() {
-        return this.element('#error-status');
-    }
-
-    get message() {
-        return this.element('#error-message');
-    }
-}
-
-describe('ErrorComponent', () => {
-    let tester: ErrorComponentTester;
-
-    let routerEvents: Subject<RouterEvent>;
-    let httpErrors: Subject<HttpError>;
-
-    beforeEach(() => {
-        routerEvents = new Subject<RouterEvent>();
-        httpErrors = new Subject<HttpError>();
-
-        TestBed.configureTestingModule({
-            declarations: [ ErrorComponent ],
-            providers: [
-                { provide: Router, useValue: { events: routerEvents } },
-                { provide: Location, useValue: { back: () => {} } }
-            ],
-            imports: [
-                HttpClientTestingModule
-            ]
-        });
-
-        const errorInterceptorService: ErrorInterceptorService = TestBed.get(ErrorInterceptorService);
-        spyOn(errorInterceptorService, 'getErrors').and.returnValue(httpErrors);
-
-        tester = new ErrorComponentTester();
-        tester.detectChanges();
-
-        jasmine.addMatchers(speculoosMatchers);
-    });
-
-    it('should not display any error initially', () => {
-        expect(tester.error).toBeNull();
-    });
-
-    it('should display an error when it is emitted, and hide it when navigation succeeds', () => {
-        httpErrors.next({
-            status: 500,
-            message: 'Oulala'
-        });
-        tester.detectChanges();
-
-        expect(tester.error).toContainText('An unexpected error occurred');
-        expect(tester.status).toContainText('Status: 500');
-        expect(tester.message).toContainText('Message: Oulala');
-
-        httpErrors.next({
-            status: null,
-            message: null
-        });
-        tester.detectChanges();
-
-        expect(tester.error).toContainText('An unexpected error occurred');
-        expect(tester.status).toBeNull();
-        expect(tester.message).toBeNull();
-
-        routerEvents.next(new NavigationStart(1, 'foo', null));
-        tester.detectChanges();
-        expect(tester.error).not.toBeNull();
-
-        routerEvents.next(new NavigationEnd(1, 'foo', null));
-        tester.detectChanges();
-        expect(tester.error).toBeNull();
-    });
-});
diff --git a/frontend/src/app/error/error.component.ts b/frontend/src/app/error/error.component.ts
deleted file mode 100644
index 66e6e4bdce437a5b034c80a5c5572d151883d0f1..0000000000000000000000000000000000000000
--- a/frontend/src/app/error/error.component.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { Component } from '@angular/core';
-import { merge, Observable } from 'rxjs';
-import { ErrorInterceptorService, HttpError } from '../error-interceptor.service';
-import { NavigationEnd, Router } from '@angular/router';
-import { filter, map } from 'rxjs/operators';
-import { Location } from '@angular/common';
-
-@Component({
-    selector: 'faidare-error',
-    templateUrl: './error.component.html',
-    styleUrls: ['./error.component.scss']
-})
-export class ErrorComponent {
-
-    error$: Observable<HttpError | null>;
-
-    constructor(
-        private router: Router,
-        private errorInterceptor: ErrorInterceptorService,
-        private location: Location
-    ) {
-        this.error$ = merge(
-            this.errorInterceptor.getErrors(),
-            this.router.events.pipe(
-                filter(event => event instanceof NavigationEnd),
-                map(() => null)
-            )
-        );
-    }
-
-    canGoBack(): boolean {
-        return window.history.length > 1;
-    }
-
-    goBack(): void {
-        this.location.back();
-    }
-}
diff --git a/frontend/src/app/facets/facets.component.html b/frontend/src/app/facets/facets.component.html
deleted file mode 100644
index dc1554b894055e9e0d6051c7ed5b2c054a0d809c..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/facets.component.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-<div class="row">
-  <faidare-small-facets
-    class="col-12 col-lg-12 col-sm-6"
-    *ngFor="let facet of facets"
-    [facet]="facet"
-    [criteria$]="criteria$"
-    [germplasmSearchCriteria$]="germplasmSearchCriteria$"
-    [displayGermplasmResult$]="displayGermplasmResult$">
-  </faidare-small-facets>
-</div>
-
-<div class="row">
-  <faidare-large-facets
-    class="col-12 col-lg-12 col-sm-6"
-    *ngFor="let facet of facets"
-    [facet]="facet"
-    [criteria$]="criteria$"
-    [germplasmSearchCriteria$]="germplasmSearchCriteria$"
-    [displayGermplasmResult$]="displayGermplasmResult$">
-  </faidare-large-facets>
-</div>
diff --git a/frontend/src/app/facets/facets.component.scss b/frontend/src/app/facets/facets.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/frontend/src/app/facets/facets.component.spec.ts b/frontend/src/app/facets/facets.component.spec.ts
deleted file mode 100644
index 2819afd6451608d1f9e73f1ce5167266a89a9889..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/facets.component.spec.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { FacetsComponent } from './facets.component';
-import { BehaviorSubject } from 'rxjs';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils
-} from '../models/data-discovery.model';
-import { GermplasmSearchCriteria } from '../models/gnpis.model';
-import { SmallFacetsComponent } from './small-facets/small-facets.component';
-import { LargeFacetsComponent } from './large-facets/large-facets.component';
-import { MockComponents } from 'ng-mocks';
-
-
-describe('FacetsComponent', () => {
-    let component: FacetsComponent;
-    let fixture: ComponentFixture<FacetsComponent>;
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            declarations: [FacetsComponent, MockComponents(SmallFacetsComponent), MockComponents(LargeFacetsComponent)]
-        })
-            .compileComponents();
-
-
-        fixture = TestBed.createComponent(FacetsComponent);
-        component = fixture.componentInstance;
-
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-        component.germplasmSearchCriteria$ = new BehaviorSubject<GermplasmSearchCriteria>(DataDiscoveryCriteriaUtils
-            .emptyGermplasmSearchCriteria());
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-        fixture.detectChanges();
-    }));
-
-    it('should create', () => {
-        expect(component).toBeTruthy();
-    });
-});
diff --git a/frontend/src/app/facets/facets.component.ts b/frontend/src/app/facets/facets.component.ts
deleted file mode 100644
index 41440ee6c693ed6f46418da757646eda53f119ea..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/facets.component.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryFacet
-} from '../models/data-discovery.model';
-import { BehaviorSubject } from 'rxjs';
-import { GermplasmSearchCriteria } from '../models/gnpis.model';
-
-export const formatFacets: {[key: string]: string} = {
-    'holdingInstitute': 'holding institute',
-    'biologicalStatus': 'biological status',
-    'geneticNature': 'genetic nature',
-    'country': 'origin country'
-};
-
-@Component({
-    selector: 'faidare-facets',
-    templateUrl: './facets.component.html',
-    styleUrls: ['./facets.component.scss']
-})
-export class FacetsComponent implements OnInit {
-
-    @Input() facets: DataDiscoveryFacet[];
-    @Input() criteria$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Input() germplasmSearchCriteria$: BehaviorSubject<GermplasmSearchCriteria>;
-    @Input() displayGermplasmResult$: BehaviorSubject<boolean>;
-
-    constructor() {
-    }
-
-    ngOnInit(): void {
-    }
-}
diff --git a/frontend/src/app/facets/large-facets/large-facets.component.html b/frontend/src/app/facets/large-facets/large-facets.component.html
deleted file mode 100644
index 93e0fe1e066eb31a33ad103d3eceb312cee2c738..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/large-facets/large-facets.component.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<ng-template #resultTemplate let-facet="result" let-t="term">
-  <ng-container *ngIf="facet !== 'REFINE'; else refine">
-    <ngb-highlight [result]="displayableKey(facet.label)"
-                   [term]="t"></ngb-highlight>
-    <small class="ml-1 text-muted">({{ facet.count | number }})</small>
-  </ng-container>
-  <ng-template #refine>
-    <div class="text-muted small">Other results are available.<br/>Refine your
-      search.
-    </div>
-  </ng-template>
-</ng-template>
-
-<ng-container *ngIf="facet.terms.length && facet.terms.length >8">
-
-  <div class="card mb-1">
-    <div class="card-body">
-      <h3
-        class="card-title">{{ formatFacets[facet.field] ? (formatFacets[facet.field] | titlecase) : facet.field | titlecase }}</h3>
-
-      <div class="mb-2">
-      <span class="badge badge-pill badge-secondary mr-1 selectedElem"
-            style="font-size: smaller"
-            *ngFor="let term of selectedTerms[facet.field]"
-            (keydown.delete)="removeKey(term)"
-            (keydown.backspace)="removeKey(term)"> {{ displaySourceName(term) }}
-        <button tabindex="-1" type="button" class="btn btn-link"
-                (click)="removeKey(term)">&times;</button>
-      </span>
-      </div>
-
-      <input #typeahead class="form-control" [formControl]="criterion"
-             [ngbTypeahead]="search"
-             (selectItem)="selectKey($event)" [resultTemplate]="resultTemplate"
-
-             placeholder="Filter on {{ facet.field.toLowerCase() }}..."
-             (focus)="focus$.next($event.target.value)"/>
-    </div>
-
-    <faidare-switch-button
-      *ngIf="!criteriaIsEmpty"
-      style="margin-top: -10px; margin-left: 25px"
-      [criteria$]=criteria$
-      [germplasmSearchCriteria$]="germplasmSearchCriteria$"
-      [displayGermplasmResult$]="displayGermplasmResult$"
-      [facetFiled]="facet.field"
-      [switchTitle]="'Germplasm details'">
-    </faidare-switch-button>
-
-  </div>
-</ng-container>
-
diff --git a/frontend/src/app/facets/large-facets/large-facets.component.scss b/frontend/src/app/facets/large-facets/large-facets.component.scss
deleted file mode 100644
index 21fbbb7047a94af8abc939ce4f2651455b6f0492..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/large-facets/large-facets.component.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-
-.card * {
-  font-size: 1em;
-}
-
-.btn-link {
-  border-top: 0;
-  border-bottom: 0;
-  margin-top: 0;
-  margin-bottom: 0;
-  padding: 0;
-  color: white;
-  vertical-align: baseline;
-  text-decoration: none;
-  font-size: inherit;
-}
-
diff --git a/frontend/src/app/facets/large-facets/large-facets.component.spec.ts b/frontend/src/app/facets/large-facets/large-facets.component.spec.ts
deleted file mode 100644
index 8529e56c0c17937065c8ab2237b090e7220d5d06..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/large-facets/large-facets.component.spec.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import { LargeFacetsComponent } from './large-facets.component';
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryFacet
-} from '../../models/data-discovery.model';
-import {
-    NgbPopoverModule,
-    NgbTypeaheadModule
-} from '@ng-bootstrap/ng-bootstrap';
-import { ReactiveFormsModule } from '@angular/forms';
-import { HttpClientTestingModule } from '@angular/common/http/testing';
-import { BehaviorSubject } from 'rxjs';
-import { GermplasmSearchCriteria } from '../../models/gnpis.model';
-import { ComponentTester } from 'ngx-speculoos';
-import { SwitchButtonComponent } from '../switch-button/switch-button.component';
-
-
-describe('LargeFacetsComponent', () => {
-    let component: LargeFacetsComponent;
-    let fixture: ComponentFixture<LargeFacetsComponent>;
-
-    class LargeFacetsComponentTester extends ComponentTester<LargeFacetsComponent> {
-        constructor() {
-            super(LargeFacetsComponent);
-        }
-
-        get  facetTitle() {
-            return this.element('h3');
-        }
-
-        get facetInput() {
-            return this.element('input');
-        }
-    }
-
-    const largeFacet: DataDiscoveryFacet = {
-        field: 'large Facet',
-        terms: [
-            {
-                term: 'source 1',
-                label: 'SOURCE 1',
-                count: 10
-            }, {
-                term: 'source 2',
-                label: 'SOURCE 2',
-                count: 20
-            }, {
-                term: 'Germplasm',
-                label: 'GERMPLASM',
-                count: 10
-            }, {
-                term: 'Traditional cultivar/landrace',
-                label: 'Traditional cultivar/landrace',
-                count: 74
-            }, {
-                term: 'Wild',
-                label: 'Wild',
-                count: 7095
-            }, {
-                term: 'Hybrid',
-                label: 'Hybrid',
-                count: 478
-            }, {
-                term: 'INRA',
-                label: 'INRA',
-                count: 74
-            }, {
-                term: 'INRA-ONF',
-                label: 'INRA-ONF',
-                count: 8282
-            }, {
-                term: 'USDA',
-                label: 'USDA',
-                count: 3871
-            }, {
-                term: 'IPK',
-                label: 'IPK',
-                count: 2606
-            }, {
-                term: 'INRA, CNRS',
-                label: 'INRA, CNRS',
-                count: 2170
-            }
-        ]
-    };
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            imports: [NgbTypeaheadModule, ReactiveFormsModule, HttpClientTestingModule, NgbPopoverModule],
-            declarations: [LargeFacetsComponent, SwitchButtonComponent]
-        })
-            .compileComponents();
-
-        fixture = TestBed.createComponent(LargeFacetsComponent);
-        component = fixture.componentInstance;
-
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-        component.germplasmSearchCriteria$ = new BehaviorSubject<GermplasmSearchCriteria>(DataDiscoveryCriteriaUtils
-            .emptyGermplasmSearchCriteria());
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-        component.facet = largeFacet;
-        fixture.detectChanges();
-    }));
-
-    it('should create', () => {
-        expect(component).toBeTruthy();
-    });
-
-    it ('should display search box', () => {
-        const tester = new LargeFacetsComponentTester();
-        component = tester.componentInstance;
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-        component.facet = largeFacet;
-        tester.detectChanges();
-
-        expect(tester.facetTitle.textContent).toEqual('Large Facet');
-        expect(tester.facetInput).toBeTruthy();
-
-    });
-});
diff --git a/frontend/src/app/facets/large-facets/large-facets.component.ts b/frontend/src/app/facets/large-facets/large-facets.component.ts
deleted file mode 100644
index 8170e0b80b9397b63242b2a7c8e81ac227171006..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/large-facets/large-facets.component.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryFacet,
-    DataDiscoverySource
-} from '../../models/data-discovery.model';
-import { BehaviorSubject, merge, Observable, Subject } from 'rxjs';
-import { distinctUntilChanged, filter, map } from 'rxjs/operators';
-import { FormControl } from '@angular/forms';
-import { NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
-import { GermplasmSearchCriteria } from '../../models/gnpis.model';
-import { GnpisService } from '../../gnpis.service';
-import { formatFacets } from '../facets.component';
-
-export type FacetTermOrRefine = {
-    term: string;
-    label: string;
-    count: number;
-} | 'REFINE';
-const maxResultsDisplayed = 8;
-
-@Component({
-    selector: 'faidare-large-facets',
-    templateUrl: './large-facets.component.html',
-    styleUrls: ['./large-facets.component.scss']
-})
-export class LargeFacetsComponent implements OnInit {
-
-    @Input() facet: DataDiscoveryFacet;
-    @Input() criteria$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Input() germplasmSearchCriteria$: BehaviorSubject<GermplasmSearchCriteria>;
-    @Input() displayGermplasmResult$: BehaviorSubject<boolean>;
-
-    @ViewChild('typeahead') typeahead: ElementRef<HTMLInputElement>;
-    formatFacets = formatFacets;
-
-    localCriteria: DataDiscoveryCriteria;
-    germplasmLocalCriteria: GermplasmSearchCriteria;
-    focus$ = new Subject<string>();
-    selectedTerms: { [key: string]: string[]; } = {};
-    criterion = new FormControl('');
-    sources: DataDiscoverySource[];
-    criteriaIsEmpty = true;
-    germplasmDisplayCurrentState = false;
-
-    constructor(private gnpisService: GnpisService) {
-    }
-
-    ngOnInit(): void {
-
-        this.gnpisService.sources$.subscribe(sources => {
-            this.sources = sources;
-        });
-
-        this.displayGermplasmResult$.subscribe(status => {
-            this.germplasmDisplayCurrentState = status;
-        });
-
-        if (this.criteria$) {
-            this.criteria$.pipe(filter(c => c !== this.localCriteria))
-                .subscribe(criteria => {
-                    this.localCriteria = { ...criteria };
-                    this.selectedTerms[this.facet.field] = criteria[this.facet.field] || [];
-                    this.criteriaIsEmpty = DataDiscoveryCriteriaUtils.checkCriteriaIsEmpty(criteria);
-                });
-        }
-
-        if (this.germplasmSearchCriteria$ && this.germplasmDisplayCurrentState) {
-            this.germplasmSearchCriteria$.pipe(filter(c => c !== this.germplasmLocalCriteria))
-                .subscribe(germplasmCriteria => {
-                    this.germplasmLocalCriteria = germplasmCriteria;
-                    this.selectedTerms[this.facet.field] = germplasmCriteria[this.facet.field] || [];
-                    this.criteriaIsEmpty = DataDiscoveryCriteriaUtils.checkCriteriaIsEmpty(germplasmCriteria);
-                });
-        }
-    }
-
-    search = (text$: Observable<string>): Observable<Array<FacetTermOrRefine>> => {
-        const inputFocus$ = this.focus$;
-        const merged$ = merge(text$, inputFocus$)
-            .pipe(
-                distinctUntilChanged(),
-                map(searchTerm => {
-                    const allMatchingBuckets = this.facet.terms
-                        // returns values not already selected
-                        .filter(terms => !this.selectedTerms[this.facet.field].includes(terms.term)
-                            // and that contains the term, ignoring the case
-                            && this.displayableKey(terms.label).toLowerCase().includes(searchTerm.toString().toLowerCase()));
-
-                    // return the first N results
-                    const result: Array<FacetTermOrRefine> = allMatchingBuckets.slice(0, maxResultsDisplayed);
-
-                    // if more results exist, add a fake refine bucket
-                    if (allMatchingBuckets.length > maxResultsDisplayed) {
-                        result.push('REFINE');
-                    }
-
-                    return result;
-                }));
-        return merged$;
-    };
-
-    displayableKey(key: string): string {
-        return key === 'NULL' ? 'None' : key;
-    }
-
-    displaySourceName(sourceId: string) {
-        for (const source of this.sources) {
-            if (source['@id'] === sourceId) {
-                return source['schema:name'];
-            }
-        }
-        return sourceId;
-    }
-
-    selectKey(event: NgbTypeaheadSelectItemEvent) {
-        event.preventDefault();
-        const selected: FacetTermOrRefine = event.item;
-        if (selected !== 'REFINE') {
-            // the item field of the event contains the facet term
-            // we push the selected key to our collection of keys
-            if (this.criteria$) {
-                if (this.localCriteria[this.facet.field]) {
-                    this.localCriteria[this.facet.field].push(event.item.term);
-                } else {
-                    this.localCriteria[this.facet.field] = [event.item.term];
-                }
-            }
-            if (this.germplasmSearchCriteria$ && this.germplasmDisplayCurrentState) {
-
-                if (event.item.term !== 'Germplasm' && this.facet.field === 'types') {
-                    if (this.localCriteria[this.facet.field]) {
-                        this.localCriteria[this.facet.field].push(event.item.term);
-                    } else {
-                        this.localCriteria[this.facet.field] = [event.item.term];
-                    }
-                    this.switchGermplasmResult();
-                }
-                if (!this.germplasmLocalCriteria[this.facet.field]) {
-                    this.germplasmLocalCriteria[this.facet.field] = [event.item.term];
-                } else {
-                    this.germplasmLocalCriteria[this.facet.field].push(event.item.term);
-                }
-            }
-            this.emitChanges();
-        }
-        this.typeahead.nativeElement.blur();
-    }
-
-    emitChanges() {
-        if (this.criteria$) {
-            this.criteria$.next(this.localCriteria);
-        }
-        if (this.germplasmSearchCriteria$ && this.germplasmDisplayCurrentState) {
-            this.germplasmSearchCriteria$.next(this.germplasmLocalCriteria);
-        }
-    }
-
-    removeKey(key: string) {
-        this.selectedTerms[this.facet.field] =
-            this.removeFromList(this.selectedTerms[this.facet.field], key);
-        if (this.criteria$ && !this.germplasmDisplayCurrentState) {
-            this.localCriteria[this.facet.field] =
-                this.removeFromList(this.localCriteria[this.facet.field], key);
-        }
-        if (this.germplasmSearchCriteria$ && this.germplasmDisplayCurrentState) {
-            if (key === 'Germplasm') {
-                this.switchGermplasmResult();
-            }
-            this.germplasmLocalCriteria[this.facet.field] =
-                this.removeFromList(this.germplasmLocalCriteria[this.facet.field], key);
-        }
-        this.emitChanges();
-    }
-
-    removeFromList(list: string[], elem: string) {
-        const index = list.indexOf(elem);
-        return [
-            ...list.slice(0, index),
-            ...list.slice(index + 1)];
-    }
-
-    switchGermplasmResult() {
-        if (!this.germplasmDisplayCurrentState) {
-            this.localCriteria = {
-                ...this.localCriteria,
-                facetFields: ['types']
-            };
-        } else {
-            this.localCriteria = {
-                ...this.localCriteria,
-                facetFields: ['types', 'sources']
-            };
-        }
-        this.criteria$.next(this.localCriteria);
-        this.displayGermplasmResult$.next(!this.germplasmDisplayCurrentState);
-    }
-}
diff --git a/frontend/src/app/facets/small-facets/small-facets.component.html b/frontend/src/app/facets/small-facets/small-facets.component.html
deleted file mode 100644
index c14fa0278731851618ba27647b08c8f14f825124..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/small-facets/small-facets.component.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<ng-template #germplasmDetailsPopup>
-  <div class="card ngb-popover-window ">
-    <br>
-    This is a button to view more information about the germplasm that are return by your search.<br>
-    You can also download the results in standard format.
-  </div>
-</ng-template>
-
-
-<div class="card mb-1" *ngIf="facet.terms.length && facet.terms.length <= 8">
-  <div class="card-body">
-    <h3
-      class="card-title">{{ formatFacets[facet.field] ? (formatFacets[facet.field] | titlecase) : facet.field | titlecase }}</h3>
-
-    <form [formGroup]="checkBoxes" class="card-text">
-      <div class="form-check" *ngFor="let term of facet.terms">
-        <input class="form-check-input"
-               type="checkbox"
-               id="{{ term.term }}"
-               [formControlName]="term.term"
-        />
-        <label class="form-check-label" for="{{ term.term }}">
-          {{ term.label }} ({{ term.count | number }})
-        </label>
-
-        <faidare-switch-button
-          style="margin-top: 5px"
-          *ngIf="term.term == 'Germplasm' && !criteriaIsEmpty"
-          [criteria$]=criteria$
-          [germplasmSearchCriteria$]="germplasmSearchCriteria$"
-          [displayGermplasmResult$]="displayGermplasmResult$"
-          [facetFiled]="facet.field"
-          [switchTitle]="'Details'">
-        </faidare-switch-button>
-      </div>
-    </form>
-  </div>
-</div>
diff --git a/frontend/src/app/facets/small-facets/small-facets.component.scss b/frontend/src/app/facets/small-facets/small-facets.component.scss
deleted file mode 100644
index 0fd05582424850d221bbf6d200d344ad9f319360..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/small-facets/small-facets.component.scss
+++ /dev/null
@@ -1,80 +0,0 @@
-
-
-.card * {
-  font-size: 1em;
-}
-
-.card h3 {
-  font-weight: bold;
-}
-.popovers{
-  cursor: pointer;
-}
-
-#switchTitle {
-  cursor: pointer;
-}
-
-/* The switch - the box around the slider */
-
-.switch {
-  position: relative;
-  display: inline-block;
-  width: 30px;
-  height: 17px;
-}
-
-/* Hide default HTML checkbox */
-.switch input {
-  opacity: 0;
-  width: 0;
-  height: 0;
-}
-/* The slider */
-.slider {
-  position: absolute;
-  cursor: pointer;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background-color: #ccc;
-  -webkit-transition: .4s;
-  transition: .4s;
-}
-
-.slider:before {
-  position: absolute;
-  content: "";
-  height: 13px;
-  width: 13px;
-  left: 2px;
-  bottom: 2px;
-  background-color: white;
-  -webkit-transition: .4s;
-  transition: .4s;
-}
-
-input:checked + .slider {
-  background-color: #2196F3;
-}
-
-input:focus + .slider {
-  box-shadow: 0 0 1px #2196F3;
-}
-
-input:checked + .slider:before {
-  -webkit-transform: translateX(15px);
-  -ms-transform: translateX(15px);
-  transform: translateX(15px);
-}
-
-/* Rounded sliders */
-.slider.round {
-  border-radius: 17px;
-}
-
-.slider.round:before {
-  border-radius: 50%;
-}
-
diff --git a/frontend/src/app/facets/small-facets/small-facets.component.spec.ts b/frontend/src/app/facets/small-facets/small-facets.component.spec.ts
deleted file mode 100644
index 491899470af2d5824ab51dfc2ff350e5c886ccba..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/small-facets/small-facets.component.spec.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-
-import { SmallFacetsComponent } from './small-facets.component';
-import { ReactiveFormsModule } from '@angular/forms';
-import { ComponentTester, speculoosMatchers } from 'ngx-speculoos';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryFacet
-} from '../../models/data-discovery.model';
-import { BehaviorSubject } from 'rxjs';
-import { take } from 'rxjs/operators';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { GermplasmSearchCriteria } from '../../models/gnpis.model';
-import { SwitchButtonComponent } from '../switch-button/switch-button.component';
-
-describe('SmallFacetsComponent', () => {
-    class FacetsComponentTester extends ComponentTester<SmallFacetsComponent> {
-        constructor() {
-            super(SmallFacetsComponent);
-        }
-
-        get title() {
-            return this.element('h3.card-title');
-        }
-
-        get terms() {
-            return this.elements('label');
-        }
-
-        get checkboxes() {
-            return this.elements('input');
-        }
-
-        get switchButton() {
-            return this.elements('label#switchTitle');
-        }
-
-    }
-
-    const exampleFacet1: DataDiscoveryFacet = {
-        field: 'sources',
-        terms: [
-            {
-                term: 'source 1',
-                label: 'SOURCE 1',
-                count: 10
-            }, {
-                term: 'source 2',
-                label: 'SOURCE 2',
-                count: 20
-            }
-        ]
-    };
-
-    const exampleFacet2: DataDiscoveryFacet = {
-        field: 'types',
-        terms: [
-            {
-                term: 'Germplasm',
-                label: 'GERMPLASM',
-                count: 10
-            }
-        ]
-    };
-
-    beforeEach(() => TestBed.configureTestingModule({
-        imports: [ReactiveFormsModule],
-        declarations: [SmallFacetsComponent, SwitchButtonComponent],
-        schemas: [NO_ERRORS_SCHEMA]
-    }));
-
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    it('should display facet', () => {
-        const tester = new FacetsComponentTester();
-
-        const component = tester.componentInstance;
-        component.facet = exampleFacet1;
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-        component.germplasmSearchCriteria$ = new BehaviorSubject<GermplasmSearchCriteria>(DataDiscoveryCriteriaUtils
-            .emptyGermplasmSearchCriteria());
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-        tester.detectChanges();
-
-        expect(tester.title).toContainText('Sources');
-
-        expect(tester.terms[0]).toContainText('SOURCE 1 (10)');
-        expect(tester.terms[0].attr('for')).toBe('source 1');
-        expect(tester.checkboxes[0].attr('id')).toBe('source 1');
-
-        expect(tester.terms[1]).toContainText('SOURCE 2 (20)');
-        expect(tester.terms[1].attr('for')).toBe('source 2');
-        expect(tester.checkboxes[1].attr('id')).toBe('source 2');
-    });
-
-    it('should initialize with criteria', () => {
-        const tester = new FacetsComponentTester();
-
-        const component = tester.componentInstance;
-        component.facet = exampleFacet1;
-
-        const criteria = {
-            ...DataDiscoveryCriteriaUtils.emptyCriteria(),
-            sources: ['source 2']
-        };
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(criteria);
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-
-        tester.detectChanges();
-
-
-        expect(tester.checkboxes[0].nativeElement['checked']).toBe(false);
-        expect(tester.checkboxes[1].nativeElement['checked']).toBe(true);
-    });
-
-    it('should change criteria on checkbox selection change', () => {
-        const tester = new FacetsComponentTester();
-
-        const component = tester.componentInstance;
-        component.facet = exampleFacet1;
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-        component.germplasmSearchCriteria$ = new BehaviorSubject<GermplasmSearchCriteria>(DataDiscoveryCriteriaUtils
-            .emptyGermplasmSearchCriteria());
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-        tester.detectChanges();
-
-        // No sources selected in criteria
-        component.criteria$.pipe(take(1)).subscribe(criteria => {
-            expect(criteria.sources).toEqual(null);
-        });
-
-        // Click on checkbox
-        // @ts-ignore
-        tester.checkboxes[1].nativeElement.click();
-        expect(tester.checkboxes[1].nativeElement['checked']).toBe(true);
-
-        // Source 2 selected
-        component.criteria$.subscribe(criteria => {
-            expect(criteria.sources).toEqual(['source 2']);
-        });
-    });
-
-    it('should display advance search button for germplasm', () => {
-        const tester = new FacetsComponentTester();
-
-        const component = tester.componentInstance;
-        const criteria = {
-            ...DataDiscoveryCriteriaUtils.emptyCriteria(),
-            types: ['Germplasm']
-        };
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(criteria);
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(true);
-        component.facet = exampleFacet2;
-        tester.detectChanges();
-
-        expect(tester.switchButton.length).toEqual(1);
-        expect(tester.switchButton[0]).toContainText('Details');
-
-    });
-
-    it('should not display advance search button for germplasm', () => {
-        const tester = new FacetsComponentTester();
-
-        const component = tester.componentInstance;
-        const criteria = {
-            ...DataDiscoveryCriteriaUtils.emptyCriteria(),
-            types: ['Germplasm', 'Phenotyping Study']
-        };
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-        component.germplasmSearchCriteria$ = new BehaviorSubject<GermplasmSearchCriteria>(DataDiscoveryCriteriaUtils
-            .emptyGermplasmSearchCriteria());
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-        component.facet = exampleFacet2;
-        tester.detectChanges();
-
-        expect(tester.switchButton).toEqual([]);
-
-    });
-});
diff --git a/frontend/src/app/facets/small-facets/small-facets.component.ts b/frontend/src/app/facets/small-facets/small-facets.component.ts
deleted file mode 100644
index 4d978e46e8f69942cef2fcad0f78d2043a68468c..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/small-facets/small-facets.component.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryFacet
-} from '../../models/data-discovery.model';
-import { FormControl, FormGroup } from '@angular/forms';
-import { BehaviorSubject } from 'rxjs';
-import { filter } from 'rxjs/operators';
-import { Params } from '@angular/router';
-import { GermplasmSearchCriteria } from '../../models/gnpis.model';
-import { formatFacets } from '../facets.component';
-
-@Component({
-    selector: 'faidare-small-facets',
-    templateUrl: './small-facets.component.html',
-    styleUrls: ['./small-facets.component.scss']
-})
-export class SmallFacetsComponent implements OnInit {
-
-    @Input() facet: DataDiscoveryFacet;
-    @Input() criteria$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Input() germplasmSearchCriteria$: BehaviorSubject<GermplasmSearchCriteria>;
-    @Input() displayGermplasmResult$: BehaviorSubject<boolean>;
-
-    @Output() changed = new EventEmitter<boolean>();
-    formatFacets = formatFacets;
-
-
-    localCriteria: DataDiscoveryCriteria;
-    germplasmLocalCriteria: GermplasmSearchCriteria;
-    criteriaIsEmpty = true;
-    queryParams: Params;
-    checkBoxes: FormGroup = new FormGroup({});
-    germplasmDisplayCurrentState = false;
-
-    constructor() {
-    }
-
-    ngOnInit(): void {
-        for (const term of this.facet.terms) {
-            const control = new FormControl(false);
-            this.checkBoxes.addControl(term.term, control);
-        }
-        if (this.facet.field === 'types') {
-            const switchControl = new FormControl(false);
-            this.checkBoxes.addControl('selectSwitchButton', switchControl);
-        }
-
-        this.displayGermplasmResult$.subscribe(value => {
-            this.germplasmDisplayCurrentState = value;
-        });
-
-        if (this.criteria$) {
-            this.criteria$.pipe(filter(c => c !== this.localCriteria))
-                .subscribe(criteria => {
-                    this.localCriteria = criteria;
-                    this.getSelectedTerms(criteria);
-
-                    this.criteriaIsEmpty = DataDiscoveryCriteriaUtils.checkCriteriaIsEmpty(criteria);
-                });
-        }
-
-        if (this.germplasmSearchCriteria$ && this.germplasmDisplayCurrentState) {
-            this.germplasmSearchCriteria$.pipe(filter(c => c !== this.germplasmLocalCriteria))
-                .subscribe(germplasmCriteria => {
-                    this.germplasmLocalCriteria = germplasmCriteria;
-                    if (this.germplasmDisplayCurrentState) {
-                        this.getSelectedTerms(germplasmCriteria);
-                    }
-                });
-        }
-
-        this.checkBoxes.valueChanges.subscribe(checkBoxesValue => {
-            const selectedTerms = Object.keys(checkBoxesValue).filter(key => checkBoxesValue[key]);
-            const multiSelection = Object.keys(checkBoxesValue).filter(key => checkBoxesValue[key] && key !== 'Germplasm');
-            const unselectGermplasm = Object.keys(checkBoxesValue).filter(key => key === 'Germplasm' && !checkBoxesValue[key]);
-
-            if ((multiSelection.length > 0 && this.facet.field === 'types') || unselectGermplasm.length > 0) {
-                this.localCriteria = {
-                    ...this.localCriteria,
-                    facetFields: ['types', 'sources'],
-                    [this.facet.field]: selectedTerms
-                };
-                this.criteria$.next(this.localCriteria);
-                this.displayGermplasmResult$.next(false);
-            }
-
-            if (this.criteria$) {
-                this.localCriteria = {
-                    ...this.localCriteria,
-                    [this.facet.field]: selectedTerms
-                };
-                this.criteria$.next(this.localCriteria);
-            }
-            if (this.germplasmSearchCriteria$ && this.germplasmDisplayCurrentState) {
-                this.germplasmLocalCriteria = {
-                    ...this.germplasmLocalCriteria,
-                    [this.facet.field]: selectedTerms
-                };
-                this.germplasmSearchCriteria$.next(this.germplasmLocalCriteria);
-            }
-        });
-    }
-
-    getSelectedTerms(criteria) {
-        const selectedTerms = criteria[this.facet.field] || [];
-
-        for (const [key, control] of Object.entries(this.checkBoxes.controls)) {
-            const isSelected = selectedTerms.indexOf(key) >= 0;
-            control.setValue(isSelected, { emitEvent: false });
-        }
-
-        this.criteriaIsEmpty = DataDiscoveryCriteriaUtils.checkCriteriaIsEmpty(criteria);
-    }
-}
diff --git a/frontend/src/app/facets/switch-button/switch-button.component.html b/frontend/src/app/facets/switch-button/switch-button.component.html
deleted file mode 100644
index 1b865ae51c239039d8636352c9ddf0fe3f9bd4e1..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/switch-button/switch-button.component.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<div id="germplasmSearch"
-     title=""
-     *ngIf="facetFiled == 'types'">
-  <label for="selectSwitchButton" style="margin-right: 5px"
-         id="switchTitle">
-    {{ switchTitle }}
-  </label>
-  <label class="switch" id="switchButton">
-    <input type="checkbox" id="selectSwitchButton"
-           [checked]="germplasmDisplayCurrentState"
-           (change)="switchGermplasmResult()">
-    <span class="slider round"></span>
-  </label>
-  <a class="btn popovers" data-boundary="window" placement="auto"
-     [autoClose]="'outside'"
-     [ngbPopover]="germplasmDetailsPopup"
-     [popoverTitle]="'Details button\'s help.'" container="body">
-
-    <img src="assets/faidare/images/question-mark.png" alt="help"
-         title="This is a button to view more information about the germplasm that are return by your search.
-                 You can also download the results in standard format."
-         height="20px" style="margin-top: -10px; margin-left: 10px"/>
-  </a>
-</div>
-
-
-<ng-template #germplasmDetailsPopup>
-  <div class="card ngb-popover-window ">
-    <br>
-    This is a button to view more information about the germplasm that are return by your search.<br>
-    You can also download the results in standard format.
-  </div>
-</ng-template>
diff --git a/frontend/src/app/facets/switch-button/switch-button.component.scss b/frontend/src/app/facets/switch-button/switch-button.component.scss
deleted file mode 100644
index 9e31a5a9c2ebbda9d5e3cadebe188c34a9666f59..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/switch-button/switch-button.component.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-
-.popovers{
-  cursor: pointer;
-}
-
-#switchTitle {
-  cursor: pointer;
-}
-
-/* The switch - the box around the slider */
-
-.switch {
-  position: relative;
-  display: inline-block;
-  width: 30px;
-  height: 17px;
-}
-
-/* Hide default HTML checkbox */
-.switch input {
-  opacity: 0;
-  width: 0;
-  height: 0;
-}
-/* The slider */
-.slider {
-  position: absolute;
-  cursor: pointer;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background-color: #ccc;
-  -webkit-transition: .4s;
-  transition: .4s;
-}
-
-.slider:before {
-  position: absolute;
-  content: "";
-  height: 13px;
-  width: 13px;
-  left: 2px;
-  bottom: 2px;
-  background-color: white;
-  -webkit-transition: .4s;
-  transition: .4s;
-}
-
-input:checked + .slider {
-  background-color: #2196F3;
-}
-
-input:focus + .slider {
-  box-shadow: 0 0 1px #2196F3;
-}
-
-input:checked + .slider:before {
-  -webkit-transform: translateX(15px);
-  -ms-transform: translateX(15px);
-  transform: translateX(15px);
-}
-
-/* Rounded sliders */
-.slider.round {
-  border-radius: 17px;
-}
-
-.slider.round:before {
-  border-radius: 50%;
-}
diff --git a/frontend/src/app/facets/switch-button/switch-button.component.spec.ts b/frontend/src/app/facets/switch-button/switch-button.component.spec.ts
deleted file mode 100644
index 927fd40c350c6244d97ade9fc12e22505675b074..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/switch-button/switch-button.component.spec.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { SwitchButtonComponent } from './switch-button.component';
-import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils
-} from '../../models/data-discovery.model';
-import { BehaviorSubject } from 'rxjs';
-
-describe('SwitchButtonComponent', () => {
-    let component: SwitchButtonComponent;
-    let fixture: ComponentFixture<SwitchButtonComponent>;
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            imports: [NgbPopoverModule],
-            declarations: [SwitchButtonComponent]
-        })
-            .compileComponents();
-    }));
-
-    it('should create', () => {
-        fixture = TestBed.createComponent(SwitchButtonComponent);
-        component = fixture.componentInstance;
-        component.displayGermplasmResult$ = new BehaviorSubject<boolean>(false);
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-        fixture.detectChanges();
-        expect(component).toBeTruthy();
-    });
-});
diff --git a/frontend/src/app/facets/switch-button/switch-button.component.ts b/frontend/src/app/facets/switch-button/switch-button.component.ts
deleted file mode 100644
index ecdb42fadaa8b073080fb4d21f398bf9e2466b73..0000000000000000000000000000000000000000
--- a/frontend/src/app/facets/switch-button/switch-button.component.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoverySource
-} from '../../models/data-discovery.model';
-import { BehaviorSubject } from 'rxjs';
-import { GermplasmSearchCriteria } from '../../models/gnpis.model';
-
-@Component({
-    selector: 'faidare-switch-button',
-    templateUrl: './switch-button.component.html',
-    styleUrls: ['./switch-button.component.scss']
-})
-export class SwitchButtonComponent implements OnInit {
-
-
-    @Input() criteria$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Input() germplasmSearchCriteria$: BehaviorSubject<GermplasmSearchCriteria>;
-    @Input() displayGermplasmResult$: BehaviorSubject<boolean>;
-    @Input() facetFiled: string;
-    @Input() switchTitle: string;
-
-    localCriteria: DataDiscoveryCriteria;
-    sources: DataDiscoverySource[];
-    criteriaIsEmpty = true;
-    germplasmDisplayCurrentState = false;
-
-    constructor() {
-    }
-
-    ngOnInit() {
-
-        this.displayGermplasmResult$.subscribe(value => {
-            this.germplasmDisplayCurrentState = value;
-        });
-
-        if (this.criteria$) {
-            this.criteria$.subscribe(criteria => {
-                this.localCriteria = criteria;
-                this.criteriaIsEmpty = DataDiscoveryCriteriaUtils.checkCriteriaIsEmpty(criteria);
-            });
-        }
-    }
-
-    switchGermplasmResult() {
-
-        this.displayGermplasmResult$.next(!this.germplasmDisplayCurrentState);
-        if (this.germplasmDisplayCurrentState) {
-            this.localCriteria = {
-                ...this.localCriteria,
-                facetFields: ['types'],
-                germplasmLists: null,
-                types: this.localCriteria.types ? this.localCriteria.types : ['Germplasm']
-            };
-        } else {
-            this.localCriteria = {
-                ...this.localCriteria,
-                facetFields: ['types', 'sources'],
-            };
-            this.germplasmSearchCriteria$.next(DataDiscoveryCriteriaUtils.emptyGermplasmSearchCriteria());
-        }
-        this.criteria$.next(this.localCriteria);
-    }
-}
diff --git a/frontend/src/app/form/form.component.html b/frontend/src/app/form/form.component.html
deleted file mode 100644
index ca5638c7b236200f01bc5cbb3450b5f5c13fc8cb..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/form.component.html
+++ /dev/null
@@ -1,84 +0,0 @@
-<ul class="nav nav-tabs">
-  <li class="nav-item">
-    <a tabindex="0"
-       class="nav-link germplasm {{ getNavClass(tabs.GERMPLASM) }}"
-       (click)="activeTab=tabs.GERMPLASM">
-      {{ tabs.GERMPLASM }}
-    </a>
-  </li>
-  <li class="nav-item"
-      *ngIf="!displayGermplasmResult">
-    <a tabindex="1"
-       class="nav-link trait {{ getNavClass(tabs.TRAIT) }}"
-       (click)="activeTab=tabs.TRAIT">
-      {{ tabs.TRAIT }}
-    </a>
-  </li>
-</ul>
-
-<!-- Germplasm tab -->
-<div class="germplasm {{ getTabClass(tabs.GERMPLASM) }}">
-  <!-- Input for the crops field -->
-  <div class="form-group row pt-3">
-    <label for="crops" class="col-sm-4">
-      <span>Crops</span>
-      <small class="small text-muted">
-        (common name, species, genus, subtaxa & synonyms)
-      </small>
-    </label>
-    <div class="col-sm-8">
-      <faidare-suggestion-field
-        inputId="crops"
-        criteriaField="crops"
-        [criteria$]="criteria$"
-        [displayGermplasmResult$]="displayGermplasmResult$"
-        placeholder="Search crops">
-      </faidare-suggestion-field>
-    </div>
-  </div>
-  <!-- Input for the germplasmList field -->
-  <div class="form-group row"
-       *ngIf="!displayGermplasmResult">
-    <label for="germplasmList" class="col-sm-4">
-      <span>Germplasm list</span>
-      <small class="small text-muted">
-        (panel, collection & population)
-      </small>
-    </label>
-    <div class="col-sm-8">
-      <faidare-suggestion-field
-        inputId="germplasmList"
-        criteriaField="germplasmLists"
-        [criteria$]="criteria$"
-        [displayGermplasmResult$]="displayGermplasmResult$"
-        placeholder="Search germplasm lists">
-      </faidare-suggestion-field>
-    </div>
-  </div>
-  <!-- Input for the accessions field -->
-  <div class="form-group row">
-    <label for="accessions" class="col-sm-4">
-      <span>Accession</span>
-      <small class="small text-muted">
-        (accession name, number & synonyms)
-      </small>
-    </label>
-    <div class="col-sm-8">
-      <faidare-suggestion-field
-        inputId="accessions"
-        criteriaField="accessions"
-        [criteria$]="criteria$"
-        [displayGermplasmResult$]="displayGermplasmResult$"
-        placeholder="Search germplasm accession">
-      </faidare-suggestion-field>
-    </div>
-  </div>
-</div>
-
-<!-- Trait tab -->
-<div class="trait {{ getTabClass(tabs.TRAIT) }}">
-  <faidare-trait-ontology-widget
-    [criteria$]="criteria$"
-    (initialized)="traitWidgetInitialized.emit($event)">
-  </faidare-trait-ontology-widget>
-</div>
diff --git a/frontend/src/app/form/form.component.scss b/frontend/src/app/form/form.component.scss
deleted file mode 100644
index e93197f5e367abca4711c2db373930f5eb17f25c..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/form.component.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-
-label {
-  span {
-    font-weight: bold;
-    display: block;
-  }
-}
-
-.nav-tabs {
-  .nav-link.active {
-    font-weight: bold;
-  }
-}
diff --git a/frontend/src/app/form/form.component.spec.ts b/frontend/src/app/form/form.component.spec.ts
deleted file mode 100644
index 1a950eed51ada86bce37eef1b50e2ecb47a1ec46..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/form.component.spec.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { FormComponent } from './form.component';
-import { MockComponents } from 'ng-mocks';
-import { SuggestionFieldComponent } from './suggestion-field/suggestion-field.component';
-import { TraitOntologyWidgetComponent } from './trait-ontology-widget/trait-ontology-widget.component';
-import { BehaviorSubject } from 'rxjs';
-
-
-describe('FormComponent', () => {
-
-    beforeEach(async(() =>
-        TestBed.configureTestingModule({
-            declarations: [
-                FormComponent, MockComponents(SuggestionFieldComponent), MockComponents(TraitOntologyWidgetComponent)
-            ],
-        }).compileComponents()
-    ));
-
-    it('should switch tabs', async(() => {
-        const fixture = TestBed.createComponent(FormComponent);
-        const component = fixture.componentInstance;
-        component.displayGermplasmResult$ = new BehaviorSubject(false);
-        fixture.detectChanges();
-
-        const element: HTMLElement = fixture.nativeElement;
-        const germplasmNav: HTMLElement = element.querySelector('a.germplasm');
-        const germplasmTab: HTMLElement = element.querySelector('div.germplasm');
-        const traitNav: HTMLElement = element.querySelector('a.trait');
-        const traitTab: HTMLElement = element.querySelector('div.trait');
-
-        // Check default tab is active
-        expect(germplasmNav.getAttribute('class')).toContain('active');
-        expect(germplasmTab.getAttribute('class')).toContain('visible');
-        expect(traitNav.getAttribute('class')).not.toContain('active');
-        expect(traitTab.getAttribute('class')).toContain('d-none');
-
-        traitNav.click();
-        fixture.detectChanges();
-
-        // Check tab switched
-        expect(traitNav.getAttribute('class')).toContain('active');
-        expect(traitTab.getAttribute('class')).toContain('visible');
-        expect(germplasmNav.getAttribute('class')).not.toContain('active');
-        expect(germplasmTab.getAttribute('class')).toContain('d-none');
-
-        germplasmNav.click();
-        fixture.detectChanges();
-
-        // Check tab switched back
-        expect(germplasmNav.getAttribute('class')).toContain('active');
-        expect(germplasmTab.getAttribute('class')).toContain('visible');
-        expect(traitNav.getAttribute('class')).not.toContain('active');
-        expect(traitTab.getAttribute('class')).toContain('d-none');
-    }));
-});
diff --git a/frontend/src/app/form/form.component.ts b/frontend/src/app/form/form.component.ts
deleted file mode 100644
index 836ed4b8d5ac8604fadf5b06866adcb47bb54fb5..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/form.component.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-import { DataDiscoveryCriteria } from '../models/data-discovery.model';
-import { BehaviorSubject } from 'rxjs';
-
-enum Tabs {
-    GERMPLASM = 'Germplasm',
-    TRAIT = 'Trait'
-}
-
-@Component({
-    selector: 'faidare-form',
-    templateUrl: './form.component.html',
-    styleUrls: ['./form.component.scss']
-})
-export class FormComponent implements OnInit {
-    @Input() criteria$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Input() displayGermplasmResult$: BehaviorSubject<boolean>;
-    @Output() traitWidgetInitialized = new EventEmitter();
-
-    // Default active tab
-    activeTab: Tabs = Tabs.GERMPLASM;
-
-    // to give access in HTML template
-    tabs = Tabs;
-    displayGermplasmResult: boolean;
-
-    getNavClass(tab: Tabs) {
-        return this.activeTab === tab ? 'active' : '';
-    }
-
-    getTabClass(tab: Tabs) {
-        return this.activeTab === tab ? 'visible' : 'd-none';
-    }
-    ngOnInit(): void {
-        this.displayGermplasmResult$.subscribe(displayStatus => {
-            this.displayGermplasmResult = displayStatus;
-            if (this.displayGermplasmResult) {
-                this.activeTab = Tabs.GERMPLASM;
-            }
-        });
-    }
-}
diff --git a/frontend/src/app/form/suggestion-field/suggestion-field.component.html b/frontend/src/app/form/suggestion-field/suggestion-field.component.html
deleted file mode 100644
index 8cac9210a4c6bc9b7f3085096210b9799187b150..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/suggestion-field/suggestion-field.component.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!-- List of selected elements -->
-<div class="mb-2">
-  <span class="badge badge-pill badge-secondary mr-1"
-        tabindex="0"
-        *ngFor="let key of selectedKeys"
-        (keydown.delete)="removeKey(key)"
-        (keydown.backspace)="removeKey(key)">
-        {{ key }}
-    <button tabindex="-1" type="button" class="btn btn-link" (click)="removeKey(key)">&times;</button>
-  </span>
-</div>
-
-<!-- Typeahead input -->
-<ng-template #resultTemplate let-r="result" let-t="term">
-  <!-- Normal term suggestion -->
-  <ngb-highlight
-    *ngIf="r !== 'REFINE'"
-    [result]="r"
-    [term]="t">
-  </ngb-highlight>
-  <!-- Refine suggestion message -->
-  <div *ngIf="r === 'REFINE'" class="text-muted small">
-    Refine your search to see more results.
-  </div>
-</ng-template>
-<input type="text"
-       class="form-control"
-       [id]="inputId"
-       #inputElement
-       #typeahead="ngbTypeahead"
-       [formControl]="input"
-       [ngbTypeahead]="search"
-       [resultTemplate]="resultTemplate"
-       (selectItem)="selectKey($event)"
-       (click)="click$.next($event.target.value)"
-       [placeholder]= "placeholder"
-/>
diff --git a/frontend/src/app/form/suggestion-field/suggestion-field.component.scss b/frontend/src/app/form/suggestion-field/suggestion-field.component.scss
deleted file mode 100644
index 469da62147452daa8c3289e1e67960c69e3f5c09..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/suggestion-field/suggestion-field.component.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-
-.btn-link {
-  border-top: 0;
-  border-bottom: 0;
-  margin-top: 0;
-  margin-bottom: 0;
-  padding: 0;
-  color: white;
-  vertical-align: baseline;
-  text-decoration: none;
-  font-size: inherit;
-}
diff --git a/frontend/src/app/form/suggestion-field/suggestion-field.component.spec.ts b/frontend/src/app/form/suggestion-field/suggestion-field.component.spec.ts
deleted file mode 100644
index f20bd4547fa0d6b7c56f1514aee1768fecf7ec16..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/suggestion-field/suggestion-field.component.spec.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { SuggestionFieldComponent } from './suggestion-field.component';
-import { ReactiveFormsModule } from '@angular/forms';
-import { NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
-import { GnpisService } from '../../gnpis.service';
-import { BehaviorSubject, of } from 'rxjs';
-import { DataDiscoveryCriteriaUtils } from '../../models/data-discovery.model';
-import { ComponentTester } from 'ngx-speculoos';
-import { HttpClientTestingModule } from '@angular/common/http/testing';
-
-
-describe('SuggestionFieldComponent', () => {
-
-    class SuggestionFieldComponentTester extends ComponentTester<SuggestionFieldComponent> {
-        constructor() {
-            super(SuggestionFieldComponent);
-        }
-    }
-
-    beforeEach(() => TestBed.configureTestingModule({
-        imports: [
-            ReactiveFormsModule,
-            NgbTypeaheadModule,
-            HttpClientTestingModule,
-        ],
-        declarations: [
-            SuggestionFieldComponent
-        ]
-    }));
-
-    it('should create', () => {
-        const tester = new SuggestionFieldComponentTester();
-        const component = tester.componentInstance;
-        component.criteria$ = new BehaviorSubject(DataDiscoveryCriteriaUtils.emptyCriteria());
-        tester.detectChanges();
-        expect(component).toBeTruthy();
-    });
-
-    it('should fetch suggestion on text change', async(() => {
-        const tester = new SuggestionFieldComponentTester();
-        const component = tester.componentInstance;
-        const criteria = DataDiscoveryCriteriaUtils.emptyCriteria();
-        component.criteria$ = new BehaviorSubject(criteria);
-        component.criteriaField = 'crops';
-
-        const expectedSuggestions = ['a', 'b', 'c'];
-        const service = TestBed.get(GnpisService) as GnpisService;
-        spyOn(service, 'suggest').and.returnValue(of(expectedSuggestions));
-        tester.detectChanges();
-
-        component.search(of('bar'))
-            .subscribe((actualSuggestions: string[]) => {
-                expect(actualSuggestions).toEqual(expectedSuggestions);
-
-                expect(service.suggest).toHaveBeenCalledWith(
-                    component.criteriaField, 10, 'bar', criteria
-                );
-            });
-    }));
-
-    it('should display the selected criteria as pills', () => {
-        const tester = new SuggestionFieldComponentTester();
-        const component = tester.componentInstance;
-        component.criteriaField = 'crops';
-        const criteria = { ...DataDiscoveryCriteriaUtils.emptyCriteria(), crops: ['Zea', 'Wheat'] };
-        component.criteria$ = new BehaviorSubject(criteria);
-
-        tester.detectChanges();
-
-        const pills = tester.nativeElement.querySelectorAll('.badge-pill');
-
-        expect(pills.length).toBe(2);
-        expect(pills[0].textContent).toContain('Zea');
-        expect(pills[1].textContent).toContain('Wheat');
-    });
-
-
-    it('should fetch suggestion', async(() => {
-        const tester = new SuggestionFieldComponentTester();
-        const component = tester.componentInstance;
-        component.criteriaField = 'crops';
-        const selectedCrops = ['Zea', 'Wheat'];
-        const criteria = { ...DataDiscoveryCriteriaUtils.emptyCriteria(), crops: selectedCrops };
-        component.criteria$ = new BehaviorSubject(criteria);
-
-        const allSuggestions = ['Zea', 'Wheat', 'Vitis', 'Grapevine'];
-        const service = TestBed.get(GnpisService) as GnpisService;
-        spyOn(service, 'suggest').and.returnValue(of(allSuggestions));
-
-        const expectedSuggestions = allSuggestions.filter(s => selectedCrops.indexOf(s) < 0);
-
-        tester.detectChanges();
-
-        component.search(of('bar'))
-            .subscribe((actualSuggestions: string[]) => {
-                expect(actualSuggestions).toEqual(expectedSuggestions.concat(['REFINE']));
-
-                expect(service.suggest).toHaveBeenCalledWith(
-                    component.criteriaField, 10, 'bar', criteria
-                );
-            });
-    }));
-});
diff --git a/frontend/src/app/form/suggestion-field/suggestion-field.component.ts b/frontend/src/app/form/suggestion-field/suggestion-field.component.ts
deleted file mode 100644
index 5b43b56d27a4de67e28cc9005889cafbadd0d75f..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/suggestion-field/suggestion-field.component.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
-import { BehaviorSubject, merge, Observable, Subject } from 'rxjs';
-import { FormControl } from '@angular/forms';
-import {
-    NgbTypeahead,
-    NgbTypeaheadSelectItemEvent
-} from '@ng-bootstrap/ng-bootstrap';
-import { GnpisService } from '../../gnpis.service';
-import { debounceTime, filter, map, switchMap } from 'rxjs/operators';
-import { DataDiscoveryCriteria } from '../../models/data-discovery.model';
-
-@Component({
-    selector: 'faidare-suggestion-field',
-    templateUrl: './suggestion-field.component.html',
-    styleUrls: ['./suggestion-field.component.scss']
-})
-export class SuggestionFieldComponent implements OnInit {
-
-    @Input() criteriaField: string;
-    @Input() inputId: string;
-    @Input() criteria$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Input() displayGermplasmResult$: BehaviorSubject<boolean>;
-    @Input() placeholder: string;
-
-    selectedKeys: string[] = [];
-
-    click$ = new Subject();
-
-    input = new FormControl();
-
-    @ViewChild('inputElement') inputElement: ElementRef;
-    @ViewChild('typeahead') typeahead: NgbTypeahead;
-
-    private localCriteria: DataDiscoveryCriteria = null;
-
-    constructor(private gnpisService: GnpisService) {
-    }
-
-    ngOnInit(): void {
-        this.criteria$
-            .pipe(filter(c => c !== this.localCriteria))
-            .subscribe(newCriteria => {
-                this.localCriteria = newCriteria;
-
-                const selectedInCriteria = newCriteria[this.criteriaField];
-                if (selectedInCriteria) {
-                    // Add selection from criteria into list of selected keys
-                    this.selectedKeys = [...selectedInCriteria];
-                } else {
-                    // Clear list of selected keys
-                    this.selectedKeys = [];
-                }
-                this.input.setValue('');
-            });
-    }
-
-    /**
-     * Search elements corresponding to the user entry and return a list of
-     * suggestions
-     */
-    search = (text$: Observable<string>): Observable<string[]> => {
-        // Observable of clicks when the suggestion popup is closed
-        const clicksWithClosedPopup$ = this.click$.pipe(
-            filter(() => !this.typeahead.isPopupOpen())
-        );
-        /*const text2$ = text$.pipe(
-            filter(term => term.length >= 2)
-        );*/
-
-        // When new text or focus or click with popup closed
-        return merge(text$, clicksWithClosedPopup$).pipe(
-            debounceTime(250),
-            switchMap((term: string) => {
-                /*if (!term) {
-                    // No term to search
-                    return of([]);
-                }*/
-
-                // Otherwise, we fetch new suggestions
-                return this.fetchSuggestion(term);
-            })
-        );
-    };
-
-    /**
-     * Fetch new suggestions for term
-     */
-    private fetchSuggestion(term: string): Observable<string[]> {
-        // Fetch suggestions
-        const suggestions$ = this.gnpisService.suggest(
-            this.criteriaField, 10, term, this.localCriteria
-        );
-
-        // Filter out already selected suggestions
-        return suggestions$.pipe(map(suggestions => {
-            suggestions.push('REFINE');
-            return this.removeAlreadySelected(suggestions);
-        }));
-    }
-
-    /**
-     * Remove suggestions that are in the current selection
-     * @param suggestions a list of suggestion
-     * @return list of suggestion that are not selected (in this.selectedKeys)
-     */
-    private removeAlreadySelected(suggestions: string[]) {
-        return suggestions.filter(suggestion => {
-            return this.selectedKeys.indexOf(suggestion) < 0;
-        });
-    }
-
-    /**
-     * Add the element selected by the user in the list of the selected elements
-     */
-    selectKey($event: NgbTypeaheadSelectItemEvent) {
-        $event.preventDefault();
-        if ($event.item !== 'REFINE') {
-            this.selectedKeys.push($event.item);
-            this.emitSelectionChange();
-
-            // Empty input value and blur
-            this.input.setValue('');
-        }
-        setTimeout(() => {
-            this.inputElement.nativeElement.blur();
-        }, 200);
-    }
-
-    /**
-     * Remove the element selected by the user in the list of the selected
-     * elements
-     */
-    removeKey(key: string) {
-        const index = this.selectedKeys.indexOf(key);
-        this.selectedKeys = [
-            ...this.selectedKeys.slice(0, index),
-            ...this.selectedKeys.slice(index + 1)
-        ];
-        this.emitSelectionChange();
-    }
-
-    /**
-     * Emit current selection when changed
-     */
-    private emitSelectionChange() {
-        this.localCriteria = {
-            ...this.localCriteria,
-            [this.criteriaField]: [...this.selectedKeys]
-        };
-        this.criteria$.next(this.localCriteria);
-        let displayGermplasmResult = false;
-        this.displayGermplasmResult$.subscribe(germplasmResultState => {
-            displayGermplasmResult = germplasmResultState;
-        });
-        this.displayGermplasmResult$.next(displayGermplasmResult);
-    }
-}
diff --git a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.html b/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.html
deleted file mode 100644
index 9fadad2b691cd3aa81640f723b9beb7d599f0ed3..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<p *ngIf="variablesList.length === 0" class="mt-1">
-  <ngb-alert [dismissible]="false">
-    <strong>Warning!</strong> No variables for the current criteria.
-  </ngb-alert>
-</p>
-
-<div id="trait-ontology-widget" class="mb-4"></div>
diff --git a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.scss b/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.scss
deleted file mode 100644
index 0b8c9a86baf16db58dfe2702049fcf359a8a6fe0..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import "~trait-ontology-widget/dist/module/cropOntologyWidget.module.css";
diff --git a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.spec.ts b/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.spec.ts
deleted file mode 100644
index 120bf39fde756f87f0e51fec772d9885b1ade3b1..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.spec.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-
-import { CropOntologyWidgetFactory, TraitOntologyWidgetComponent } from './trait-ontology-widget.component';
-import { GnpisService } from '../../gnpis.service';
-import { BehaviorSubject, of } from 'rxjs';
-import { DataDiscoveryCriteriaUtils } from '../../models/data-discovery.model';
-import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap';
-import { HttpClientTestingModule } from '@angular/common/http/testing';
-
-describe('TraitOntologyWidgetComponent', () => {
-    const fakeWidget = {
-        setHeight() {},
-        reset() {},
-        setSelectedNodeIds() {},
-        showOnly() {},
-        addSelectionChangeHandler() {},
-        jsTreePanel: {
-            jstree: {
-                get_top_selected() {
-                    return ['A', 'B'];
-                },
-                get_bottom_selected() {
-                    return ['a', 'b', 'c'];
-                },
-                select_node(id) {}
-            },
-            load() {
-                return {
-                    then(callback) {
-                        callback();
-                    }
-                };
-            }
-        }
-    };
-
-    const fakeFactory: CropOntologyWidgetFactory = {
-        initialize() {
-            return fakeWidget;
-        }
-    };
-
-
-    beforeEach(() => TestBed.configureTestingModule({
-        imports: [NgbAlertModule, HttpClientTestingModule],
-        declarations: [
-            TraitOntologyWidgetComponent
-        ],
-        providers: [
-            { provide: CropOntologyWidgetFactory, useValue: fakeFactory }
-        ]
-    }));
-
-
-    it('should create', () => {
-        const fixture = TestBed.createComponent(TraitOntologyWidgetComponent);
-        const component = fixture.componentInstance;
-        component.criteria$ = new BehaviorSubject(DataDiscoveryCriteriaUtils.emptyCriteria());
-
-        const service = TestBed.get(GnpisService) as GnpisService;
-        spyOn(service, 'suggest').and.returnValue(of(['var1', 'var2']));
-
-        fixture.detectChanges();
-
-        expect(component).toBeTruthy();
-    });
-
-
-    it('should initialize selection from criteria', () => {
-        const fixture = TestBed.createComponent(TraitOntologyWidgetComponent);
-        const component = fixture.componentInstance;
-        const criteria = DataDiscoveryCriteriaUtils.emptyCriteria();
-        criteria.topSelectedTraitOntologyIds = fakeWidget.jsTreePanel.jstree.get_top_selected();
-
-        const expectedBottomIds = fakeWidget.jsTreePanel.jstree.get_bottom_selected();
-
-        component.criteria$ = new BehaviorSubject(criteria);
-
-        const service = TestBed.get(GnpisService) as GnpisService;
-        spyOn(service, 'suggest').and.returnValue(of(['var1', 'var2']));
-
-        fixture.detectChanges();
-
-        expect(component.criteria$.value.observationVariableIds).toEqual(expectedBottomIds);
-    });
-});
diff --git a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.ts b/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.ts
deleted file mode 100644
index 42b943b9bc2b255aa7b366e5279c7c491139c0ec..0000000000000000000000000000000000000000
--- a/frontend/src/app/form/trait-ontology-widget/trait-ontology-widget.component.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import { Component, EventEmitter, Injectable, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
-import { CropOntologyWidget } from 'trait-ontology-widget/dist/module/cropOntologyWidget.module';
-import { DataDiscoveryCriteria } from '../../models/data-discovery.model';
-import { BehaviorSubject } from 'rxjs';
-import { GnpisService } from '../../gnpis.service';
-import { filter } from 'rxjs/operators';
-
-@Injectable({
-    providedIn: 'root',
-})
-export class CropOntologyWidgetFactory {
-
-    initialize(...args): CropOntologyWidget {
-        return new CropOntologyWidget(...args);
-    }
-
-}
-
-@Component({
-    selector: 'faidare-trait-ontology-widget',
-    templateUrl: './trait-ontology-widget.component.html',
-    styleUrls: ['./trait-ontology-widget.component.scss'],
-
-    // Necessary to import CSS style from the trait ontology widget
-    encapsulation: ViewEncapsulation.None
-})
-export class TraitOntologyWidgetComponent implements OnInit {
-
-    @Input() criteria$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Output() initialized = new EventEmitter();
-
-    variablesList: string[] = [];
-
-    private localCriteria: DataDiscoveryCriteria = null;
-
-    private widget: CropOntologyWidget;
-
-    constructor(private gnpisService: GnpisService,
-                private widgetFactory: CropOntologyWidgetFactory) {
-    }
-
-    ngOnInit() {
-        this.widget = this.widgetFactory.initialize(
-            '#trait-ontology-widget', {
-                breedingAPIEndpoint: 'brapi/v1/',
-                showCheckBoxes: true,
-                useSearchField: true
-            }
-        );
-        this.widget.setHeight(450);
-
-        let initialized = false;
-        this.criteria$
-            .pipe(filter(c => c !== this.localCriteria))
-            .subscribe(newCriteria => {
-                this.localCriteria = newCriteria;
-
-                if (!initialized) {
-                    const selectedNodeIds = this.localCriteria.topSelectedTraitOntologyIds;
-                    this.widget.jsTreePanel.load().then(() => {
-                        this.setSelected(selectedNodeIds);
-                        this.localCriteria.observationVariableIds = this.getBottomSelected();
-                        this.initialized.emit(true);
-                    });
-                    initialized = true;
-                } else {
-                    this.widget.reset();
-                }
-
-                const field = 'observationVariableIds';
-
-                this.gnpisService.suggest(field, null, '', this.localCriteria)
-                    .subscribe(ids => {
-                        this.variablesList = ids;
-                        this.widget.showOnly(ids);
-                    });
-            });
-
-        this.widget.addSelectionChangeHandler(() => {
-            this.localCriteria = {
-                ...this.localCriteria,
-                observationVariableIds: this.getBottomSelected(),
-                topSelectedTraitOntologyIds: this.getTopSelected()
-            };
-            this.criteria$.next(this.localCriteria);
-        });
-    }
-
-    private setSelected(selectedNodeIds: string[]) {
-        if (selectedNodeIds) {
-            for (const nodeId of selectedNodeIds) {
-                this.widget.jsTreePanel.jstree.select_node(nodeId);
-            }
-        }
-    }
-
-    private getTopSelected(): string[] {
-        return this.widget.jsTreePanel.jstree.get_top_selected();
-    }
-
-    private getBottomSelected(): string[] {
-        return this.widget.jsTreePanel.jstree.get_bottom_selected();
-    }
-}
diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.html b/frontend/src/app/germplasm-card/germplasm-card.component.html
deleted file mode 100644
index 188729a86340ebc0e6e7cf62af5e51473016601f..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-card/germplasm-card.component.html
+++ /dev/null
@@ -1,789 +0,0 @@
-<faidare-loading-spinner [loading]="loading" class="float-right"></faidare-loading-spinner>
-
-<ng-container *ngIf="germplasmGnpis">
-  <h3 class="mb-4">
-    <img *ngIf="!loading && germplasmGnpis.holdingGenbank && germplasmGnpis.holdingGenbank.instituteName"
-         [src]="germplasmGnpis.holdingGenbank.logo"
-         align="right"/>
-    Germplasm: {{ germplasmGnpis.germplasmName }}
-  </h3>
-
-  <!-- Display the map -->
-  <faidare-map [locations]="germplasmLocations"></faidare-map>
-
-  <div class="row align-items-center justify-content-center">
-
-    <!--Templates for gerplasm card-->
-
-    <ng-template #taxonTemplate>
-      <faidare-card-row
-        label="Genus"
-        [test]="germplasmGnpis.genus">
-        <ng-template>
-          <i>{{ germplasmGnpis.genus }}</i>
-        </ng-template>
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Species"
-        [test]="germplasmGnpis.species">
-        <ng-template>
-          <i>{{ germplasmGnpis.species }}</i>
-          {{ germplasmGnpis.speciesAuthority ? '(' + germplasmGnpis.speciesAuthority + ')' : '' }}
-        </ng-template>
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Subtaxa"
-        [test]="germplasmGnpis.subtaxa">
-        <ng-template>
-          <i>{{ germplasmGnpis.subtaxa }}</i>
-          {{ germplasmGnpis.subtaxaAuthority ? '(' + germplasmGnpis.subtaxaAuthority + ')' : '' }}
-        </ng-template>
-      </faidare-card-row>
-
-
-      <faidare-card-row
-        label="Authority"
-        [test]="germplasmTaxonAuthor">
-        <ng-template>
-          {{ germplasmTaxonAuthor }}
-        </ng-template>
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Taxon ID"
-        [test]="taxonIdsWithURL && taxonIdsWithURL.length > 0">
-        <ng-template>
-          <ng-container *ngFor="let taxonRef of taxonIdsWithURL">
-
-            <faidare-card-row
-              [label]="taxonRef.sourceName"
-              [test]="taxonRef.url">
-              <ng-template>
-                <a [href]="taxonRef.url" target="_blank">
-                  {{ taxonRef.taxonId }}
-                </a>
-              </ng-template>
-            </faidare-card-row>
-
-            <faidare-card-row
-              [label]="taxonRef.sourceName"
-              [test]="!taxonRef.url">
-              <ng-template>
-                {{ taxonRef.taxonId }}
-              </ng-template>
-            </faidare-card-row>
-
-          </ng-container>
-        </ng-template>
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Comment"
-        [test]="germplasmGnpis.taxonComment">
-        <ng-template>
-          {{ germplasmGnpis.taxonComment }}
-        </ng-template>
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Taxon common names"
-        [test]="germplasmGnpis.taxonCommonNames && germplasmGnpis.taxonCommonNames.length > 0">
-        <ng-template>
-          <div class="content-overflow">
-            {{ germplasmGnpis.taxonCommonNames.join(', ') }}
-          </div>
-        </ng-template>
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Taxon synonyms"
-        [test]="germplasmGnpis.taxonSynonyms && germplasmGnpis.taxonSynonyms.length > 0">
-        <ng-template>
-          <div class="content-overflow">
-            <i>{{ germplasmGnpis.taxonSynonyms.join(', ') }}</i>
-          </div>
-        </ng-template>
-      </faidare-card-row>
-    </ng-template>
-
-    <ng-template #instituteTemplate let-logo="logo" let-code="instituteCode" let-acronym="acronym"
-                 let-organisation="organisation" let-type="instituteType" let-webSite="webSite" let-address="address">
-      <faidare-card-row
-        label=""
-        [test]="logo">
-        <ng-template>
-          <img
-            [src]="logo"/>
-        </ng-template>
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Code"
-        [value]="code">
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Acronym"
-        [value]="acronym">
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Organisation"
-        [value]="organisation">
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Type"
-        [value]="type">
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Address"
-        [value]="address">
-      </faidare-card-row>
-
-      <faidare-card-row
-        label="Website"
-        [test]="webSite">
-        <ng-template>
-          <a [href]="webSite" target="_blank">
-            {{ webSite }}
-          </a>
-        </ng-template>
-      </faidare-card-row>
-    </ng-template>
-
-    <ng-template #holdingInstituteTemplate>
-      <ng-container *ngTemplateOutlet="instituteTemplate;context:germplasmGnpis.holdingInstitute">
-      </ng-container>
-    </ng-template>
-
-    <ng-template #collectorInstituteTemplate>
-      <ng-container *ngTemplateOutlet="instituteTemplate;context:germplasmGnpis.collector.institute">
-      </ng-container>
-    </ng-template>
-
-    <ng-template #breederInstituteTemplate>
-      <ng-container *ngTemplateOutlet="instituteTemplate;context:germplasmGnpis.breeder.institute">
-      </ng-container>
-    </ng-template>
-
-    <!--Section for the image representing the germplasm and the details about this image-->
-    <div class="col-auto field" *ngIf="germplasmGnpis.photo && germplasmGnpis.photo.thumbnailFile">
-      <a class="btn popovers" data-boundary="window" placement="auto"
-         [autoClose]="'outside'"
-         [ngbPopover]="imageTemplate"
-         [popoverTitle]="germplasmGnpis.photo.photoName" container="body">
-        <img
-          [src]="germplasmGnpis.photo.thumbnailFile"
-          class="img-fluid">
-
-        <figcaption class="figure-caption" style="color: #0f6fa1;">
-          © {{ germplasmGnpis.photo.copyright }}
-        </figcaption>
-      </a>
-
-      <ng-template #imageTemplate>
-        <div class="card ngb-popover-window ">
-          <img class="card-img-top"
-               [src]="germplasmGnpis.photo.file"
-               alt="" style="max-width:500px; max-height:550px">
-          <div class="card-body">
-
-            <faidare-card-row
-              label="Accession name"
-              [value]="germplasmGnpis.germplasmName">
-            </faidare-card-row>
-
-            <faidare-card-row
-              label="Photo name"
-              [value]="germplasmGnpis.photo.photoName">
-            </faidare-card-row>
-
-            <faidare-card-row
-              label="Description"
-              [value]="germplasmGnpis.photo.description">
-            </faidare-card-row>
-
-            <faidare-card-row
-              label="Copyright"
-              [value]="'© '+germplasmGnpis.photo.copyright">
-            </faidare-card-row>
-          </div>
-        </div>
-      </ng-template>
-    </div>
-
-    <!--Section for the information about the identification of the germplasm-->
-    <faidare-card-section
-      class="col-12 col-lg"
-      header="Identification">
-      <ng-template>
-        <div class="card-body card-section-body">
-
-          <faidare-card-row
-            label="Germplasm name"
-            [value]="germplasmGnpis.germplasmName">
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Accession number"
-            [value]="germplasmGnpis.accessionNumber">
-          </faidare-card-row>
-
-          <!-- Display generic document details (PUI, data source links, etc.) -->
-          <faidare-card-generic-document
-            [document]="germplasmGnpis"
-            documentType="germplasm">
-          </faidare-card-generic-document>
-
-          <faidare-card-row
-            label="Accession synonyms"
-            [test]="germplasmGnpis.synonyms && germplasmGnpis.synonyms.length > 0">
-            <ng-template>
-              <div class="content-overflow">
-                {{ germplasmGnpis.synonyms.join(', ') }}
-              </div>
-            </ng-template>
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Taxon"
-            [test]="germplasmTaxon">
-            <ng-template>
-              <a class="popover-underline" data-boundary="window" placement="auto"
-                 [autoClose]="'outside'"
-                 [ngbPopover]="taxonTemplate"
-                 [popoverTitle]="germplasmTaxon"
-                 container="body">
-                <i>{{ germplasmTaxon }}</i>
-                {{ germplasmTaxonAuthor ? '(' + germplasmTaxonAuthor + ')' : '' }}
-              </a>
-            </ng-template>
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Biological status"
-            [value]="germplasmGnpis.biologicalStatusOfAccessionCode">
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Genetic nature"
-            [value]="germplasmGnpis.geneticNature">
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Seed source"
-            [value]="germplasmGnpis.seedSource">
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Pedigree"
-              [value]="germplasmGnpis.pedigree">
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Comments"
-            [value]="germplasmGnpis.comment">
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="Origin site"
-            [test]="germplasmGnpis.originSite && germplasmGnpis.originSite.siteName">
-            <ng-template>
-              <a [routerLink]="['/sites/', germplasmGnpis.originSite.siteId]">
-                {{ germplasmGnpis.originSite.siteName }}
-              </a>
-            </ng-template>
-          </faidare-card-row>
-
-          <faidare-card-row
-            label="MLS status"
-            [test]="germplasmMcpd && germplasmMcpd.mlsStatus">
-            <ng-template>
-              {{ germplasmMcpd.mlsStatus }}
-            </ng-template>
-          </faidare-card-row>
-
-        </div>
-      </ng-template>
-    </faidare-card-section>
-  </div>
-
-  <!--Section for the information about the holding of the germplasm-->
-  <faidare-card-section
-    header="Depositary"
-    [test]="germplasmGnpis.holdingInstitute">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-        <faidare-card-row
-          label="Institution">
-          <ng-template>
-            <a class="popover-underline" data-boundary="window" placement="auto"
-               [autoClose]="'outside'"
-               [ngbPopover]="holdingInstituteTemplate"
-               [popoverTitle]="germplasmGnpis.holdingInstitute.instituteName"
-               container="body">
-              {{ germplasmGnpis.holdingInstitute.instituteName }}</a>
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Stock center name"
-          [test]="germplasmGnpis.holdingGenbank && germplasmGnpis.holdingGenbank.instituteName && germplasmGnpis.holdingGenbank.webSite">
-          <ng-template>
-            <a [href]="germplasmGnpis.holdingGenbank.webSite" target="_blank">
-              {{ germplasmGnpis.holdingGenbank.instituteName }}
-            </a>
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Stock center name"
-          [test]="germplasmGnpis.holdingGenbank && germplasmGnpis.holdingGenbank.instituteName && !germplasmGnpis.holdingGenbank.webSite">
-          <ng-template>
-            {{ germplasmGnpis.holdingGenbank.instituteName }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Presence status"
-          [value]="germplasmGnpis.presenceStatus">
-        </faidare-card-row>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--Section for the information about the collector of the germplasm-->
-  <faidare-card-section
-    header="Collector"
-    [test]="checkCollecting()">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-        <faidare-card-row
-          label="Collecting site"
-          [test]="germplasmGnpis.collectingSite && germplasmGnpis.collectingSite.siteName">
-          <ng-template>
-            <a [routerLink]="['/sites/', germplasmGnpis.collectingSite.siteId]">
-              {{ germplasmGnpis.collectingSite.siteName }}
-            </a>
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Acquisition Source Code"
-          [test]="germplasmMcpd && germplasmMcpd.acquisitionSourceCode">
-          <ng-template>
-            {{ germplasmMcpd.acquisitionSourceCode }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Material type"
-          [test]="germplasmGnpis.collector && germplasmGnpis.collector.materialType">
-          <ng-template>
-            {{ germplasmGnpis.collector.materialType }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Collectors"
-          [test]="germplasmGnpis.collector && germplasmGnpis.collector.collectors">
-          <ng-template>
-            {{ germplasmGnpis.collector.collectors }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Acquisition / Creation date"
-          [test]="germplasmGnpis.collector && germplasmGnpis.collector.accessionCreationDate">
-          <ng-template>
-            {{ germplasmGnpis.collector.accessionCreationDate }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Acquisition / Creation date"
-          [test]="germplasmGnpis.acquisitionDate && !germplasmGnpis.collector.accessionCreationDate">
-          <ng-template>
-            {{ germplasmGnpis.acquisitionDate }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Institution"
-          [test]="germplasmGnpis.collector && germplasmGnpis.collector.institute && germplasmGnpis.collector.institute.instituteName">
-          <ng-template>
-            <a class="popover-underline" data-boundary="window" placement="auto"
-               [autoClose]="'outside'"
-               [ngbPopover]="collectorInstituteTemplate"
-               [popoverTitle]="germplasmGnpis.collector.institute.instituteName">
-              {{ germplasmGnpis.collector.institute.instituteName }}
-            </a>
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Accession number"
-          [test]="germplasmGnpis.collector && germplasmGnpis.collector.accessionNumber">
-          <ng-template>
-            {{ germplasmGnpis.collector.accessionNumber }}
-          </ng-template>
-        </faidare-card-row>
-
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--Section for the information about the breeder of the germplasm-->
-  <faidare-card-section
-    header="Breeder"
-    [test]="checkBreeder()">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-        <faidare-card-row
-          label="Institute"
-          [test]="germplasmGnpis.breeder.institute && germplasmGnpis.breeder.institute.instituteName">
-          <ng-template>
-            <a class="popover-underline" data-boundary="window" placement="auto"
-               [autoClose]="'outside'"
-               [ngbPopover]="breederInstituteTemplate"
-               [popoverTitle]="germplasmGnpis.breeder.institute.instituteName">
-              {{ germplasmGnpis.breeder.institute.instituteName }}
-            </a>
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Accession creation year"
-          [value]="germplasmGnpis.breeder.accessionCreationDate ">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Accession number"
-          [value]="germplasmGnpis.breeder.accessionNumber">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Catalog registration year"
-          [value]="germplasmGnpis.breeder.registrationYear">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Catalog deregistration year"
-          [value]="germplasmGnpis.breeder.deregistrationYear">
-        </faidare-card-row>
-
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--Section for the information about the donor of the germplasm-->
-  <faidare-card-section
-    header="Donor"
-    [test]="germplasmGnpis.donors && germplasmGnpis.donors.length > 0">
-    <ng-template>
-      <div class="table-responsive scroll-table table-card-body">
-        <faidare-card-table
-          [headers]="[
-                'Institute name',
-                'Institute code',
-                'Donation date',
-                'Accession number',
-                'Accession PUI'
-                ]"
-          [rows]="germplasmGnpis.donors">
-          <ng-template let-row>
-            <tr *ngIf="row.donorInstitute">
-              <ng-template #donorInstituteTemplate>
-                <ng-container *ngTemplateOutlet="instituteTemplate;context:row.donorInstitute">
-                </ng-container>
-              </ng-template>
-
-              <td>
-                <a class="popovers" placement="auto"
-                   [autoClose]="'outside'"
-                   [ngbPopover]="donorInstituteTemplate"
-                   [popoverTitle]="row.donorInstitute.instituteName">
-                  {{ row.donorInstitute.instituteName }}
-                </a>
-              </td>
-              <td>{{ row.donorInstituteCode }}</td>
-              <td>{{ row.donationDate }}</td>
-              <td>{{ row.donorAccessionNumber }}</td>
-              <td>{{ row.donorGermplasmPUI }}</td>
-            </tr>
-          </ng-template>
-        </faidare-card-table>
-
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--Section for the information about the distributor of the germplasm-->
-  <faidare-card-section
-    header="Distributor"
-    [test]="germplasmGnpis.distributors && germplasmGnpis.distributors.length>0">
-    <ng-template>
-      <div class="table-responsive scroll-table table-card-body">
-
-        <!--TODO : Add order column when ordering URL will be available-->
-        <faidare-card-table
-          [headers]="[
-        'Institute',
-        'Accession number',
-        'Distribution status'
-        ]"
-          [rows]="germplasmGnpis.distributors">
-          <ng-template let-row>
-            <tr>
-              <ng-template #distributorInstituteTemplate>
-                <ng-container *ngTemplateOutlet="instituteTemplate;context:row.institute">
-                </ng-container>
-              </ng-template>
-
-              <td>
-                <a class="popovers" placement="auto"
-                   [autoClose]="'outside'"
-                   [ngbPopover]="distributorInstituteTemplate"
-                   [popoverTitle]="row.institute.instituteName">
-                  {{ row.institute.instituteName }}
-                </a>
-              </td>
-              <td>{{ row.accessionNumber }}</td>
-              <td>{{ row.distributionStatus }}</td>
-            </tr>
-          </ng-template>
-
-        </faidare-card-table>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--Section for the information about the primary descriptors of the germplasm-->
-  <faidare-card-section
-    header="Evaluation Data"
-    [test]="germplasmAttributes && germplasmAttributes.length > 0">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-        <ng-container *ngFor="let descriptor of germplasmAttributes">
-          <faidare-card-row
-            [label]="descriptor.attributeName"
-            [value]="descriptor.value">
-          </faidare-card-row>
-        </ng-container>
-
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--Section for the information about the genealoggy of the germplasm-->
-  <faidare-card-section
-    header="Genealogy"
-    [test]="checkPedigree() || checkProgeny()">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-        <faidare-card-row
-          label="Crossing plan"
-          [test]="germplasmPedigree && germplasmPedigree.crossingPlan">
-          <ng-template>
-            {{ germplasmPedigree.crossingPlan }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Crossing year"
-          [test]="germplasmPedigree && germplasmPedigree.crossingYear">
-          <ng-template>
-            {{ germplasmPedigree.crossingYear }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Family code"
-          [test]="germplasmPedigree && germplasmPedigree.familyCode">
-          <ng-template>
-            {{ germplasmPedigree.familyCode }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Parent accessions"
-          [test]="germplasmPedigree && germplasmPedigree.parent1Name">
-
-          <ng-template>
-            <faidare-card-row
-              [label]="germplasmPedigree.parent1Type"
-              [test]="germplasmPedigree && germplasmPedigree.parent1DbId">
-              <ng-template>
-                <a [routerLink]="['/germplasm']"
-                   [queryParams]="{id:germplasmPedigree.parent1DbId}">
-                  {{ germplasmPedigree.parent1Name }}
-                </a>
-              </ng-template>
-            </faidare-card-row>
-
-            <faidare-card-row
-              [label]="germplasmPedigree.parent2Type"
-              [test]="germplasmPedigree && germplasmPedigree.parent2DbId">
-              <ng-template>
-                <a [routerLink]="['/germplasm']"
-                   [queryParams]="{id:germplasmPedigree.parent2DbId}">
-                  {{ germplasmPedigree.parent2Name }}
-                </a>
-              </ng-template>
-            </faidare-card-row>
-
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Sibling accession"
-          [test]="germplasmPedigree && (germplasmPedigree.siblings && germplasmPedigree.siblings.length > 0)">
-          <ng-template>
-
-            <div class="content-overflow">
-              <ng-container *ngFor="let sibling of germplasmPedigree.siblings">
-                <a [routerLink]="['/germplasm']" [queryParams]="{id:sibling.germplasmDbId }">
-                  {{ sibling.defaultDisplayName }}
-                </a>
-              </ng-container>
-            </div>
-
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Descendant"
-          [test]="checkProgeny()">
-        </faidare-card-row>
-
-        <div class="content-overflow-big">
-          <ng-container *ngFor="let child of germplasmProgeny">
-
-            <faidare-card-row class="text"
-                              [label]="child.secondParentName ? 'child(ren) of ' + child.firstParentName + ' x ' + child.secondParentName : 'child(ren) of ' + child.firstParentName"
-                              [test]="checkProgeny()">
-              <ng-template>
-
-                <ng-container *ngFor="let sibling of child.sibblings">
-                  <a [routerLink]="['/germplasm']" [queryParams]="{pui:sibling.pui}">
-                    {{ sibling.name }}
-                  </a>
-                </ng-container>
-
-              </ng-template>
-            </faidare-card-row>
-          </ng-container>
-        </div>
-
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--Section for the information about the population, collection and panel of the germplasm-->
-  <faidare-card-section
-    header="Population"
-    [test]="germplasmGnpis.population && germplasmGnpis.population.length > 0">
-    <ng-template>
-      <div class="card-body card-section-body card-section-body">
-        <ng-container *ngFor="let population of germplasmGnpis.population">
-
-          <faidare-card-row
-            [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"
-            [test]="population.germplasmRef && population.germplasmRef.pui && population.germplasmRef.pui != germplasmGnpis.germplasmPUI">
-            <ng-template>
-              <a [routerLink]="['/germplasm']"
-                 [queryParams]="{pui:population.germplasmRef.pui}">
-                {{ population.germplasmRef.name }}
-              </a> is composed by <a
-              [routerLink]="['/']"
-              [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}">
-              {{ population.germplasmCount }} accessions
-            </a>
-            </ng-template>
-          </faidare-card-row>
-
-          <faidare-card-row
-            [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"
-            [test]="population.germplasmRef && population.germplasmRef.pui && population.germplasmRef.pui == germplasmGnpis.germplasmPUI">
-            <ng-template>
-              {{ population.germplasmRef.name }} is composed by <a
-              [routerLink]="['/']"
-              [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}">
-              {{ population.germplasmCount }} accessions
-            </a>
-            </ng-template>
-          </faidare-card-row>
-
-          <faidare-card-row
-            [label]="population.type ? population.name + ' (' + population.type + ')' : population.name"
-            [test]="!population.germplasmRef">
-            <ng-template>
-              <a [routerLink]="['/']"
-                 [queryParams]="{germplasmLists: population.name, types: 'Germplasm'}">
-                {{ population.germplasmCount }} accessions
-              </a>
-            </ng-template>
-          </faidare-card-row>
-
-        </ng-container>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <faidare-card-section
-    header="Collection"
-    [test]="germplasmGnpis.collection && germplasmGnpis.collection.length > 0">
-    <ng-template>
-      <div class="card-body card-section-body">
-        <ng-container *ngFor="let collection of germplasmGnpis.collection">
-
-          <faidare-card-row
-            [label]="collection.type ? collection.name + ' (' + collection.type + ')' : collection.name">
-            <ng-template>
-              <a [routerLink]="['/']"
-                 [queryParams]="{germplasmLists: collection.name, types: 'Germplasm'}">
-                {{ collection.germplasmCount }} accessions
-              </a>
-            </ng-template>
-          </faidare-card-row>
-
-        </ng-container>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <faidare-card-section
-    header="Panel"
-    [test]="germplasmGnpis.panel && germplasmGnpis.panel.length > 0">
-    <ng-template>
-      <div class="card-body card-section-body">
-        <ng-container *ngFor="let panel of germplasmGnpis.panel">
-          <faidare-card-row
-            [label]="panel.type ? panel.name.replace(toReplace, ' ') + ' (' + panel.type + ')' :
-            panel.name.replace(toReplace,' ')">
-            <ng-template>
-              <a [routerLink]="['/']"
-                 [queryParams]="{germplasmLists: panel.name, types: 'Germplasm'}">
-                {{ panel.germplasmCount }} accessions
-              </a>
-            </ng-template>
-          </faidare-card-row>
-
-        </ng-container>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!-- XRefs part -->
-  <faidare-xrefs [xrefId]="germplasmGnpis.germplasmDbId"></faidare-xrefs>
-</ng-container>
-
diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.scss b/frontend/src/app/germplasm-card/germplasm-card.component.scss
deleted file mode 100644
index f0376501baaeced5c8d3194b0d2d23faff4269fe..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-card/germplasm-card.component.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-@import "theme";
-@import '../../styles.scss';
-
-a:not([href]):not([tabindex]) {
-  color: #0f6fa1;
-  cursor: pointer;
-}
-
-a:not([href]):not([tabindex]):hover {
-  text-decoration: underline;
-}
diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts b/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts
deleted file mode 100644
index 4f0d779fd44741e9649e3321bb997730dd9a0089..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-card/germplasm-card.component.spec.ts
+++ /dev/null
@@ -1,364 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-import { GermplasmCardComponent } from './germplasm-card.component';
-import { ComponentTester, speculoosMatchers } from 'ngx-speculoos';
-import { GnpisService } from '../gnpis.service';
-import { BrapiService } from '../brapi.service';
-import { ActivatedRoute, convertToParamMap } from '@angular/router';
-import { RouterTestingModule } from '@angular/router/testing';
-import { of } from 'rxjs';
-
-import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap';
-import { MomentModule } from 'ngx-moment';
-import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component';
-import { CardSectionComponent } from '../card-section/card-section.component';
-import { CardRowComponent } from '../card-row/card-row.component';
-import { CardTableComponent } from '../card-table/card-table.component';
-import { MapComponent } from '../map/map.component';
-import {
-    BrapiCollectingSite,
-    BrapiGermplasmAttributes,
-    BrapiGermplasmMcpd,
-    BrapiGermplasmPedigree,
-    BrapiInstitute,
-    BrapiResult,
-    BrapiSibling
-} from '../models/brapi.model';
-import {
-    Donor,
-    Germplasm,
-    GermplasmInstitute,
-    GermplasmSet,
-    Institute
-} from '../models/gnpis.model';
-import { DataDiscoverySource } from '../models/data-discovery.model';
-import { MockComponent } from 'ng-mocks';
-import { XrefsComponent } from '../xrefs/xrefs.component';
-import { CardGenericDocumentComponent } from '../card-generic-document/card-generic-document.component';
-
-
-describe('GermplasmCardComponent', () => {
-
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    class GermplasmCardComponentTester extends ComponentTester<GermplasmCardComponent> {
-        constructor() {
-            super(GermplasmCardComponent);
-        }
-
-        get title() {
-            return this.element('h3');
-        }
-
-        get cardHeader() {
-            return this.elements('div.card-header');
-        }
-
-        get cardRowField() {
-            return this.elements('div.field');
-        }
-
-        get cardRowValue() {
-            return this.elements('div.value');
-        }
-    }
-
-    const brapiSibling: BrapiSibling = {
-        germplasmDbId: 'frere1',
-        defaultDisplayName: 'frere1'
-    };
-
-
-    const brapiGermplasmPedigree: BrapiResult<BrapiGermplasmPedigree> = {
-        metadata: null,
-        result: {
-            germplasmDbId: '12',
-            defaultDisplayName: '12',
-            pedigree: null,
-            crossingPlan: null,
-            crossingYear: null,
-            familyCode: null,
-            parent1DbId: '11',
-            parent1Name: 'parent',
-            parent1Type: 'SELF',
-            parent2DbId: null,
-            parent2Name: null,
-            parent2Type: null,
-            siblings: [brapiSibling]
-        }
-    };
-
-    /*const brapiGermplasmProgeny: GermplasmResult<BrapiGermplasmProgeny> = {
-        result: {
-            germplasmDbId: '11',
-            defaultDisplayName: '11',
-            progeny: [brapiSibling]
-        }
-    };*/
-
-    const gnpisInstitute: Institute = {
-        instituteName: 'urgi',
-        instituteCode: 'inra',
-        acronym: 'urgi',
-        organisation: 'inra',
-        instituteType: 'labo',
-        webSite: 'www.labo.fr',
-        address: '12',
-        logo: null
-    };
-
-    const brapiInstitute: BrapiInstitute = {
-        instituteName: 'INRAE URGI',
-        instituteCode: '78000',
-        acronym: 'INRAE',
-        organisation: 'inrae',
-        instituteType: 'lab',
-        webSite: 'www.labo.fr',
-        instituteAddress: '18',
-        logo: null
-    };
-
-    const gnpisGermplasmInstitute: GermplasmInstitute = {
-        ...gnpisInstitute,
-        institute: gnpisInstitute,
-        accessionNumber: '12',
-        accessionCreationDate: '1993',
-        materialType: 'feuille',
-        collectors: null,
-        registrationYear: '1996',
-        deregistrationYear: '1912',
-        distributionStatus: null
-    };
-
-    const collectingSite: BrapiCollectingSite = {
-        locationDbId: 'FR-78-INRAE',
-        locationName: 'Versailles',
-        coordinateUncertainty: null,
-        elevation: null,
-        georeferencingMethod: null,
-        latitudeDecimal: null,
-        latitudeDegrees: null,
-        locationDescription: null,
-        longitudeDecimal: null,
-        longitudeDegrees: null,
-        spatialReferenceSystem: null,
-    };
-
-    const gnpisDonor: Donor = {
-        donorInstitute: gnpisInstitute,
-        donorGermplasmPUI: '12',
-        donorAccessionNumber: '12',
-        donorInstituteCode: 'urgi',
-        donationDate: null
-    };
-
-    const gnpisGermplasmSet: GermplasmSet = {
-        germplasmCount: 12,
-        germplasmRef: null,
-        id: 12,
-        name: 'truc',
-        type: 'plan'
-    };
-
-    const brapiGermplasmAttributes: BrapiResult<BrapiGermplasmAttributes> = {
-        metadata: null,
-        result: {
-            germplasmDbId: '12',
-            data: [{
-                attributeName: 'longueur',
-                value: '30',
-                attributeDbId: '1',
-                attributeCode: 'longeur',
-                determinedDate: 'today'
-            }]
-        }
-    };
-
-    const source: DataDiscoverySource = {
-        '@id': 'src1',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'source1',
-        'schema:url': 'srcUrl',
-        'schema:image': null
-    };
-
-    const germplasmTest: Germplasm = {
-        germplasmDbId: 'test',
-        defaultDisplayName: 'test',
-        accessionNumber: 'test',
-        germplasmName: 'testName',
-        germplasmPUI: 'doi:1256',
-        pedigree: 'tree',
-        seedSource: 'inra',
-        synonyms: null,
-        commonCropName: null,
-        instituteCode: 'grc12',
-        instituteName: 'institut',
-        biologicalStatusOfAccessionCode: null,
-        countryOfOriginCode: null,
-        typeOfGermplasmStorageCode: null,
-        taxonIds: null,
-        genus: 'genre',
-        species: 'esp',
-        speciesAuthority: 'L',
-        subtaxa: null,
-        subtaxaAuthority: null,
-        donors: [gnpisDonor],
-        acquisitionDate: null,
-        genusSpecies: null,
-        genusSpeciesSubtaxa: null,
-        taxonSynonyms: ['pomme', 'api'],
-        taxonCommonNames: ['pomme', 'api'],
-        taxonComment: null,
-        geneticNature: null,
-        comment: null,
-        photo: null,
-        holdingInstitute: gnpisInstitute,
-        holdingGenbank: gnpisInstitute,
-        presenceStatus: null,
-        children: null,
-        originSite: null,
-        collectingSite: null,
-        evaluationSites: null,
-        collector: gnpisGermplasmInstitute,
-        breeder: gnpisGermplasmInstitute,
-        distributors: [gnpisGermplasmInstitute],
-        panel: [gnpisGermplasmSet],
-        collection: [gnpisGermplasmSet],
-        population: [gnpisGermplasmSet],
-        'schema:includedInDataCatalog': source
-    };
-
-    const germplasmMcpdTest: BrapiGermplasmMcpd = {
-        groupId: '0',
-        accessionNames: ['test accession'],
-        accessionNumber: '01',
-        acquisitionDate: '2021',
-        acquisitionSourceCode: 'FR-urgi',
-        alternateIDs: ['Id1', 'Id2'],
-        ancestralData: null,
-        biologicalStatusOfAccessionCode: 'maintained',
-        breedingInstitutes: brapiInstitute,
-        collectingInfo: {
-            collectingDate: '2021',
-            collectingInstitutes: brapiInstitute,
-            collectingMissionIdentifier: '007',
-            collectingNumber: '3',
-            collectors: 'urgi',
-            materialType: 'germplasm',
-            collectingSite: collectingSite,
-        },
-        commonCropName: 'wheat',
-        countryOfOriginCode: 'FR',
-        donorInfo: {
-            donorAccessionNumber: 'ING007',
-            donorInstitute: brapiInstitute,
-            donationDate: '2021',
-        },
-        genus: 'Triti',
-        germplasmDbId: 'Fr-007',
-        germplasmPUI: 'urn/fr-007',
-        instituteCode: 'FR-INRAE',
-        mlsStatus: '0',
-        remarks: null,
-        safetyDuplicateInstitutes: null,
-        species: 'Triti',
-        speciesAuthority: null,
-        storageTypeCodes: null,
-        subtaxon: null,
-        subtaxonAuthority: null,
-        breederAccessionNumber: null,
-        breedingCreationYear: null,
-        catalogRegistrationYear: null,
-        catalogDeregistrationYear: null,
-        originLocationDbId: 'FR-Ver',
-        originLocationName: 'Versailles',
-        holdingInstitute: brapiInstitute,
-        holdingGenbank: brapiInstitute,
-        geneticNature: 'hybrid',
-        presenceStatus: null,
-        distributorInfos: null
-    };
-    const germplasmMcpdTestResult: BrapiResult<BrapiGermplasmMcpd> = {
-        metadata: null,
-        result: germplasmMcpdTest
-    };
-
-    const gnpisService = jasmine.createSpyObj(
-        'GnpisService', [
-            'getGermplasm',
-            'getSource'
-        ]
-    );
-    gnpisService.getGermplasm.and.returnValue(of(germplasmTest));
-    gnpisService.getSource.and.returnValue(of(source));
-
-    const brapiService = jasmine.createSpyObj(
-        'BrapiService', [
-            // 'germplasmProgeny',
-            'germplasmPedigree',
-            'germplasmAttributes',
-            'germplasmMcpd'
-        ]
-    );
-    // brapiService.germplasmProgeny.and.returnValue(of(brapiGermplasmProgeny));
-    brapiService.germplasmPedigree.and.returnValue(of(brapiGermplasmPedigree));
-    brapiService.germplasmAttributes.and.returnValue(of(brapiGermplasmAttributes));
-    brapiService.germplasmMcpd.and.returnValue(of(germplasmMcpdTestResult));
-
-
-    const activatedRouteParams = {
-        queryParams: of({ id: 'test' }),
-        snapshot: {
-            queryParams: convertToParamMap({
-                id: 'test'
-            })
-        }
-    };
-
-
-    beforeEach(async(() => {
-
-        TestBed.configureTestingModule({
-            imports: [RouterTestingModule, NgbPopoverModule, MomentModule],
-            declarations: [
-                GermplasmCardComponent, LoadingSpinnerComponent, MockComponent(XrefsComponent), CardSectionComponent,
-                CardRowComponent, LoadingSpinnerComponent, CardTableComponent,
-                MapComponent, MockComponent(CardGenericDocumentComponent)
-            ],
-            providers: [
-                { provide: BrapiService, useValue: brapiService },
-                { provide: GnpisService, useValue: gnpisService },
-                { provide: ActivatedRoute, useValue: activatedRouteParams },
-            ]
-        });
-    }));
-
-    it('should fetch germplasm information', async(() => {
-        const tester = new GermplasmCardComponentTester();
-        const component = tester.componentInstance;
-        tester.detectChanges();
-
-        component.loaded.then(() => {
-            expect(component.germplasmGnpis).toBeTruthy();
-            expect(component.germplasmMcpd).toBeTruthy();
-            tester.detectChanges();
-            expect(tester.title).toContainText('Germplasm: test');
-            expect(tester.cardHeader[0]).toContainText('Identification');
-            expect(tester.cardRowField[0]).toContainText('Germplasm name');
-            expect(tester.cardRowValue[0]).toContainText('testName');
-
-            expect(tester.cardHeader[1]).toContainText('Depositary');
-            expect(tester.cardHeader[2]).toContainText('Collector');
-            expect(tester.cardHeader[3]).toContainText('Breeder');
-            expect(tester.cardHeader[4]).toContainText('Donor');
-            expect(tester.cardHeader[5]).toContainText('Distributor');
-            expect(tester.cardHeader[6]).toContainText('Evaluation Data');
-
-            expect(tester.cardRowField[5]).toContainText('MLS status');
-            expect(tester.cardRowValue[5]).toContainText('0');
-        });
-    }));
-
-})
-;
-
diff --git a/frontend/src/app/germplasm-card/germplasm-card.component.ts b/frontend/src/app/germplasm-card/germplasm-card.component.ts
deleted file mode 100644
index 2569cee684c4e6d78bbdb8393855d96c11963374..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-card/germplasm-card.component.ts
+++ /dev/null
@@ -1,246 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { ActivatedRoute } from '@angular/router';
-import { BrapiService } from '../brapi.service';
-import { GnpisService } from '../gnpis.service';
-import {
-    BrapiAttributeData,
-    BrapiGermplasmMcpd,
-    BrapiGermplasmPedigree,
-    BrapiLocation,
-    BrapiTaxonIds,
-} from '../models/brapi.model';
-import { Children, Germplasm, Site } from '../models/gnpis.model';
-import { environment } from '../../environments/environment';
-
-@Component({
-    selector: 'faidare-germplasm-card',
-    templateUrl: './germplasm-card.component.html',
-    styleUrls: ['./germplasm-card.component.scss']
-})
-
-export class GermplasmCardComponent implements OnInit {
-
-    constructor(private brapiService: BrapiService,
-                private gnpisService: GnpisService,
-                private route: ActivatedRoute) {
-    }
-
-    taxonIdsWithURL: BrapiTaxonIds[] = [];
-    germplasmGnpis: Germplasm;
-    germplasmMcpd: BrapiGermplasmMcpd;
-    germplasmPedigree: BrapiGermplasmPedigree;
-    germplasmProgeny: Children[];
-    germplasmAttributes: BrapiAttributeData[];
-    germplasmLocations: BrapiLocation[] = [];
-    germplasmTaxon: string;
-    germplasmTaxonAuthor: string;
-    toReplace = /_/g;
-
-    loaded: Promise<void>;
-    loading = true;
-
-    async ngOnInit() {
-        this.route.queryParams.subscribe(() => {
-            const { id, pui } = this.route.snapshot.queryParams;
-
-            this.loaded = this.gnpisService.getGermplasm({ id, pui }).toPromise()
-                .then(germplasm => {
-                    const germplasmId = id || germplasm.germplasmDbId;
-                    this.germplasmGnpis = germplasm;
-                    this.reformatData();
-
-                    // TODO use the progeny call when the information about parent will be added.
-                    /*const germplasmProgeny$ = this.brapiService.germplasmProgeny(germplasmId).toPromise();
-                    germplasmProgeny$
-                        .then(germplasmProgeny => {
-                            this.germplasmProgeny = germplasmProgeny.result;
-                        });*/
-
-
-                    this.brapiService.germplasmMcpd(germplasmId).subscribe(germplasmMcpd => {
-                        this.germplasmMcpd = germplasmMcpd.result;
-                    });
-                    this.getTaxon();
-
-                    this.germplasmPedigree = null;
-                    this.brapiService.germplasmPedigree(germplasmId)
-                        .subscribe(germplasmPedigree => {
-                            this.germplasmPedigree = germplasmPedigree.result;
-                        });
-
-                    this.germplasmAttributes = [];
-                    this.brapiService.germplasmAttributes(germplasmId)
-                        .subscribe(germplasmAttributes => {
-                            if (germplasmAttributes.result && germplasmAttributes.result.data) {
-                                this.germplasmAttributes = germplasmAttributes.result.data.sort(this.compareAttributes);
-                            }
-                        });
-
-                    this.loading = false;
-                });
-        });
-
-    }
-
-    getTaxon() {
-        if (this.germplasmGnpis.genusSpeciesSubtaxa) {
-            this.germplasmTaxon = this.germplasmGnpis.genusSpeciesSubtaxa;
-            this.germplasmTaxonAuthor = this.germplasmGnpis.subtaxaAuthority;
-        } else if (this.germplasmGnpis.genusSpecies) {
-            this.germplasmTaxon = this.germplasmGnpis.genusSpecies;
-            this.germplasmTaxonAuthor = this.germplasmGnpis.speciesAuthority;
-        } else if (this.germplasmGnpis.subtaxa) {
-            this.germplasmTaxon = this.germplasmGnpis.genus + ' ' + this.germplasmGnpis.species + ' ' + this.germplasmGnpis.subtaxa;
-            this.germplasmTaxonAuthor = this.germplasmGnpis.subtaxaAuthority;
-        } else if (this.germplasmGnpis.species) {
-            this.germplasmTaxon = this.germplasmGnpis.genus + ' ' + this.germplasmGnpis.species;
-            this.germplasmTaxonAuthor = this.germplasmGnpis.speciesAuthority;
-        } else {
-            this.germplasmTaxon = this.germplasmGnpis.genus;
-            this.germplasmTaxonAuthor = '';
-        }
-    }
-
-    // TODO: do this in ETL!
-    reformatData() {
-        if (this.germplasmGnpis.children) {
-            this.germplasmProgeny = this.germplasmGnpis.children.sort();
-        }
-        if (this.germplasmGnpis.donors) {
-            this.germplasmGnpis.donors.sort(this.compareDonorInstitutes);
-        }
-        if (this.germplasmGnpis.collection) {
-            this.germplasmGnpis.collection.sort(this.compareCollectionPopulationPanel);
-        }
-        if (this.germplasmGnpis.population) {
-            this.germplasmGnpis.population.sort(this.compareCollectionPopulationPanel);
-        }
-        if (this.germplasmGnpis.panel) {
-            this.germplasmGnpis.panel.sort(this.compareCollectionPopulationPanel);
-        }
-        if (this.germplasmGnpis.collectingSite) {
-            this.germplasmGnpis.collectingSite.siteId = btoa('urn:URGI/location/' + this.germplasmGnpis.collectingSite.siteId);
-            this.siteToBrapiLocation(this.germplasmGnpis.collectingSite);
-        }
-        if (this.germplasmGnpis.originSite) {
-            this.germplasmGnpis.originSite.siteId = btoa('urn:URGI/location/' + this.germplasmGnpis.originSite.siteId);
-            this.siteToBrapiLocation(this.germplasmGnpis.originSite);
-        }
-        if (this.germplasmGnpis.evaluationSites && this.germplasmGnpis.evaluationSites.length > 0) {
-            for (const site of this.germplasmGnpis.evaluationSites) {
-                site.siteId = btoa('urn:URGI/location/' + site.siteId);
-                this.siteToBrapiLocation(site);
-            }
-        }
-        if (this.germplasmGnpis.taxonIds && this.germplasmGnpis.taxonIds.length > 0) {
-            this.addRefURL(this.germplasmGnpis.taxonIds);
-        }
-        // TODO: to remove when extractor script will be up-to-date
-        if (this.germplasmGnpis.holdingGenbank) {
-            this.germplasmGnpis.holdingGenbank.logo = 'https://urgi.versailles.inra.fr/files/siregal/images/grc/inra_brc_en.png';
-        }
-    }
-
-    // TODO: do this in ETL!
-    siteToBrapiLocation(site: Site) {
-        if (site && site.siteId && site.latitude && site.longitude) {
-            this.germplasmLocations.push({
-                locationDbId: site.siteId,
-                locationName: site.siteName,
-                locationType: site.siteType,
-                latitude: site.latitude,
-                longitude: site.longitude
-            });
-        }
-    }
-
-    addRefURL(taxonIds: BrapiTaxonIds[]) {
-        for (const taxonId of taxonIds) {
-            if (environment.taxaLinks[taxonId.sourceName]) {
-                taxonId.url = environment.taxaLinks[taxonId.sourceName] + taxonId.taxonId;
-            } else {
-                taxonId.url = null;
-            }
-            this.taxonIdsWithURL.push(taxonId);
-        }
-    }
-
-    // TODO: use a generic function to get path in object (or null if non-existent)
-    checkProgeny() {
-        return (this.germplasmProgeny
-            && this.germplasmProgeny.length > 0);
-    }
-
-    checkBreeder() {
-        return (this.germplasmGnpis.breeder)
-            && ((this.germplasmGnpis.breeder.institute && this.germplasmGnpis.breeder.institute.instituteName)
-                || this.germplasmGnpis.breeder.accessionCreationDate
-                || this.germplasmGnpis.breeder.accessionNumber
-                || this.germplasmGnpis.breeder.registrationYear
-                || this.germplasmGnpis.breeder.deregistrationYear);
-    }
-
-    checkPedigree() {
-        return (this.germplasmPedigree
-            && (this.germplasmPedigree.parent1Name
-                || this.germplasmPedigree.parent2Name
-                || this.germplasmPedigree.crossingPlan
-                || this.germplasmPedigree.crossingYear
-                || this.germplasmPedigree.familyCode)
-        );
-    }
-
-    checkCollectorInstituteObject() {
-        return (
-            this.germplasmGnpis.collector
-            && this.germplasmGnpis.collector.institute
-            && this.germplasmGnpis.collector.institute.instituteName);
-    }
-
-    checkCollectorInstituteFields() {
-        return (this.germplasmGnpis.collector) &&
-            (this.germplasmGnpis.collector.accessionNumber
-                || this.germplasmGnpis.collector.accessionCreationDate
-                || this.germplasmGnpis.collector.materialType
-                || this.germplasmGnpis.collector.collectors
-                || this.germplasmGnpis.collector.registrationYear
-                || this.germplasmGnpis.collector.deregistrationYear
-                || this.germplasmGnpis.collector.distributionStatus
-            );
-    }
-
-    checkCollecting() {
-        return (this.germplasmGnpis.collectingSite && this.germplasmGnpis.collectingSite.siteName)
-            || (this.checkCollectorInstituteObject() || this.checkCollectorInstituteFields());
-    }
-
-    compareDonorInstitutes(a, b) {
-        if (a.donorInstitute.instituteName < b.donorInstitute.instituteName) {
-            return -1;
-        }
-        if (a.donorInstitute.instituteName > b.donorInstitute.instituteName) {
-            return 1;
-        }
-        return 0;
-    }
-
-    compareAttributes(a, b) {
-        if (a.attributeName < b.attributeName) {
-            return -1;
-        }
-        if (a.attributeName > b.attributeName) {
-            return 1;
-        }
-        return 0;
-    }
-
-    compareCollectionPopulationPanel(a, b) {
-        if (a.name < b.name) {
-            return -1;
-        }
-        if (a.name > b.name) {
-            return 1;
-        }
-        return 0;
-    }
-}
diff --git a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.html b/frontend/src/app/germplasm-result-page/germplasm-result-page.component.html
deleted file mode 100644
index feda59ea7d9f7c4c359d38729226913315f4902e..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.html
+++ /dev/null
@@ -1,134 +0,0 @@
-<ng-container *ngIf="germplasms && germplasms.length>0">
-
-  <div class="container mb-3">
-    <div class="row result align-content-center">
-          <span class="col mt-2 bolder">
-            Results:
-          </span>
-      <div class="row align-content-center">
-  <span *ngIf="pagination.totalResult" style="margin-right: 5px"
-        class="col align-self-end small text-muted mt-3">
-        From {{ pagination.startResult | number }}
-    to {{ pagination.endResult | number }}
-    over {{ pagination.totalResult | number }} documents
-      <span *ngIf="pagination.totalResult > pagination.maxResults">
-      (limited to {{ pagination.maxResults | number }})
-      </span>
-  </span>
-      </div>
-    </div>
-  </div>
-
-  <div *ngIf="overLimitSizeExport" class="alert alert-warning alert-dismissible fade show" role="alert">
-   You must filter your results to have less than <strong>50,000 results</strong> before exporting the data.
-  </div>
-
-  <button type="button" class="btn btn-outline-success btn-sm mb-2"
-          (click)="exportPlantMaterial(localCriteria)">
-    <span class="iconify" data-icon="fa-solid:file-csv" data-inline="false"></span>
-    Export Plant Material list
-  </button>
-
-<!--TODO Activate when export webservice will be ready-->
-<!--  <button type="button" class="btn btn-outline-info btn-sm ml-3  mb-2"-->
-<!--          (click)="exportMcpd(localCriteria)">-->
-<!--    <span class="iconify" data-icon="fa-solid:file-csv" data-inline="false"></span>-->
-<!--    Export MCPD list-->
-<!--  </button>-->
-
-  <!-- Loading spinner-->
-  <div class="text-center">
-    <faidare-loading-spinner [loading]="loading"></faidare-loading-spinner>
-  </div>
-
-  <faidare-card-section
-    class="col-12 col-lg"
-    header="Germplasm data: "
-    [test]="germplasms">
-    <ng-template>
-      <div class="table-responsive table-card-body">
-        <table class="table table-sm table-striped">
-          <thead>
-          <tr>
-            <th id="germplasmResultThead"
-                *ngFor="let header of headers" scope="col">
-              <label id="tabHeader"
-                     (click)="getTabField(header)">{{ formatHeaders[header] }}
-                <i *ngIf="!fieldSortState[header]" class="fa fa-sort"
-                   aria-hidden="true"></i>
-                <i *ngIf="fieldSortState[header] =='desc'"
-                   class="fa fa-sort-desc"
-                   aria-hidden="true"></i>
-                <i *ngIf="fieldSortState[header] == 'asc'"
-                   class="fa fa-sort-asc"
-                   aria-hidden="true"></i>
-              </label>
-            </th>
-          </tr>
-          </thead>
-          <tbody>
-          <ng-container *ngFor="let germplasm of germplasms">
-            <tr>
-              <td>
-                <a [routerLink]="['/germplasm']"
-                   [queryParams]="{id: germplasm.germplasmDbId}"
-                   target="_blank">
-                  {{ germplasm.germplasmName }}
-                </a>
-              </td>
-              <td>{{ germplasm.accessionNumber }}</td>
-              <td>{{ germplasm.genusSpecies }}</td>
-              <td>{{ germplasm.instituteName }}</td>
-              <td>{{ germplasm.biologicalStatusOfAccessionCode }}</td>
-              <td>{{ germplasm.countryOfOriginCode }}</td>
-            </tr>
-          </ng-container>
-          </tbody>
-        </table>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <div class="container text-right"
-       style="margin-top: -30px"
-       *ngIf="germplasms">
-    <div ngbDropdown class="dropdown-container">
-      <button class="btn btn-outline-secondary btn-sm"
-              ngbDropdownToggle>Results per page : {{ pagination.pageSize }}
-      </button>
-      <div ngbDropdownMenu class="dropdown-menu" id="pageSizes">
-        <div *ngFor="let pageSize of elementPerPage">
-          <button type="button"
-                  class="btn btn-light"
-                  (click)="changeNbElementPerPage(pageSize)"
-                  style="width: 160px;" ngbDropdownItem>{{ pageSize }}
-          </button>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <div class="d-flex justify-content-center mt-2 mb-5"
-       *ngIf="pagination.totalPages > 1">
-    <!-- we add 1 to the page because ngb-pagination is 1 based -->
-    <ngb-pagination [page]="pagination.currentPage + 1"
-                    (pageChange)="changePage($event)"
-                    [collectionSize]="resultCount()"
-                    [pageSize]="pagination.pageSize"
-                    [maxSize]="5"
-                    [boundaryLinks]="true"
-                    [ellipses]="false"
-                    size="sm">
-    </ngb-pagination>
-  </div>
-
-</ng-container>
-
-
-<div *ngIf="germplasms && germplasms.length == 0"
-     id="no-results" class="text-center">
-  <div class="no-result-icon">
-    <span class="fa fa-meh-o"></span>
-  </div>
-  No results.
-</div>
diff --git a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.scss b/frontend/src/app/germplasm-result-page/germplasm-result-page.component.scss
deleted file mode 100644
index 7579016a3ec6d8f426d3ffd20228f766480dcd43..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-@import "theme";
-@import '../../styles.scss';
-
-
-#tabHeader {
-  cursor: pointer;
-}
-
-#germplasmResultThead {
-  margin-top: 26px;
-  border-bottom-width: 3px;
-  border-bottom-color: #d0d8e1;
-}
-
-
-.result {
-  border-top: 4.5px solid #c2c2c2;
-  border-bottom: 1px solid #c2c2c2;
-}
-
-.no-result-icon {
-  font-size: 8rem;
-  color: $gray-300;
-}
-
-.bolder {
-  font-size: 1.2rem;
-  font-weight: bold;
-}
-
-thead th {
-  position: sticky;
-  top: 0;
-  background-color: white;
-}
-
-label {
-  span {
-    font-weight: bold;
-    display: block;
-  }
-}
-
-
-.iconify {
-  width: 35px;
-  height: 35px; }
diff --git a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.spec.ts b/frontend/src/app/germplasm-result-page/germplasm-result-page.component.spec.ts
deleted file mode 100644
index 786c51b78ca6d746b9bd81248d02a2a1e1ae693b..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.spec.ts
+++ /dev/null
@@ -1,302 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { GermplasmResultPageComponent } from './germplasm-result-page.component';
-import { RouterTestingModule } from '@angular/router/testing';
-import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component';
-import { GnpisService } from '../gnpis.service';
-import { GermplasmResults } from '../models/brapi.model';
-import { CardSectionComponent } from '../card-section/card-section.component';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryFacet,
-    DEFAULT_PAGE_SIZE,
-    MAX_RESULTS
-} from '../models/data-discovery.model';
-import { Germplasm, GermplasmSearchCriteria } from '../models/gnpis.model';
-import { BehaviorSubject, of } from 'rxjs';
-
-
-describe('GermplasmResultPageComponent', () => {
-    let component: GermplasmResultPageComponent;
-    let fixture: ComponentFixture<GermplasmResultPageComponent>;
-
-    const pagination = {
-        startResult: 1,
-        endResult: DEFAULT_PAGE_SIZE,
-        totalResult: 2,
-        currentPage: 0,
-        pageSize: DEFAULT_PAGE_SIZE,
-        totalPages: 1,
-        totalCount: 2,
-        maxResults: MAX_RESULTS
-    };
-
-    const facets: DataDiscoveryFacet[] = [
-        {
-            field: 'holdingInstitute',
-            terms: [
-                {
-                    term: 'INRA',
-                    label: 'INRA',
-                    count: 74
-                },
-                {
-                    term: 'INRA-ONF',
-                    label: 'INRA-ONF',
-                    count: 8282
-                },
-                {
-                    term: 'USDA',
-                    label: 'USDA',
-                    count: 3871
-                },
-                {
-                    term: 'IPK',
-                    label: 'IPK',
-                    count: 2606
-                },
-                {
-                    term: 'INRA, CNRS',
-                    label: 'INRA, CNRS',
-                    count: 2170
-                }
-            ]
-        },
-        {
-            field: 'biologicalStatus',
-            terms: [
-                {
-                    term: 'Traditional cultivar/landrace',
-                    label: 'Traditional cultivar/landrace',
-                    count: 74
-                },
-                {
-                    term: 'Wild',
-                    label: 'Wild',
-                    count: 7095
-                },
-                {
-                    term: 'Hybrid',
-                    label: 'Hybrid',
-                    count: 478
-                }
-            ]
-        }
-    ];
-
-    const germplasmSearchResult: GermplasmResults<Germplasm> = {
-        metadata: {
-            pagination: pagination
-        },
-        facets: facets,
-        result: {
-            data: [{
-                germplasmDbId: 'g1',
-                defaultDisplayName: 'germplam1',
-                accessionNumber: 'G_10',
-                germplasmName: 'germplam1',
-                germplasmPUI: 'urn_g1',
-                pedigree: null,
-                seedSource: 'Versaille Institute',
-                synonyms: null,
-                commonCropName: 'cheery',
-                instituteCode: '78',
-                instituteName: 'Versaille Institute',
-                biologicalStatusOfAccessionCode: null,
-                countryOfOriginCode: 'FR',
-                typeOfGermplasmStorageCode: null,
-                taxonIds: null,
-                genus: 'Populus',
-                species: 'x generosa',
-                speciesAuthority: 'Pop',
-                subtaxa: 'subsp',
-                subtaxaAuthority: '',
-                donors: null,
-                acquisitionDate: 'yesterday',
-
-
-                genusSpecies: null,
-                genusSpeciesSubtaxa: null,
-                taxonSynonyms: null,
-                taxonCommonNames: null,
-                taxonComment: null,
-                geneticNature: null,
-                comment: null,
-                photo: null,
-                holdingInstitute: null,
-                holdingGenbank: null,
-                presenceStatus: null,
-                children: null,
-                originSite: null,
-                collectingSite: null,
-                evaluationSites: null,
-                collector: null,
-                breeder: null,
-                distributors: null,
-                panel: null,
-                collection: null,
-                population: null,
-                'schema:includedInDataCatalog': null
-            }, {
-                germplasmDbId: 'g2',
-                defaultDisplayName: 'germplam2',
-                accessionNumber: 'G_20',
-                germplasmName: 'germplam2',
-                germplasmPUI: 'urn_g2',
-                pedigree: null,
-                seedSource: 'Versaille Institute',
-                synonyms: null,
-                commonCropName: 'cheery',
-                instituteCode: '78',
-                instituteName: 'Versaille Institute',
-                biologicalStatusOfAccessionCode: null,
-                countryOfOriginCode: 'FR',
-                typeOfGermplasmStorageCode: null,
-                taxonIds: null,
-                genus: 'Triticum',
-                species: 'aestivum',
-                speciesAuthority: 'Trit',
-                subtaxa: 'subsp',
-                subtaxaAuthority: '',
-                donors: null,
-                acquisitionDate: 'today',
-
-
-                genusSpecies: null,
-                genusSpeciesSubtaxa: null,
-                taxonSynonyms: null,
-                taxonCommonNames: null,
-                taxonComment: null,
-                geneticNature: null,
-                comment: null,
-                photo: null,
-                holdingInstitute: null,
-                holdingGenbank: null,
-                presenceStatus: null,
-                children: null,
-                originSite: null,
-                collectingSite: null,
-                evaluationSites: null,
-                collector: null,
-                breeder: null,
-                distributors: null,
-                panel: null,
-                collection: null,
-                population: null,
-                'schema:includedInDataCatalog': null
-
-            }],
-        }
-    };
-
-
-
-
-
-
-    const criteria: GermplasmSearchCriteria = {
-        accessionNumbers: ['G_20'],
-        germplasmDbIds: null,
-        germplasmGenus: null,
-        germplasmNames: ['germplam1'],
-        germplasmPUIs: null,
-        germplasmSpecies: null,
-
-        synonyms: null,
-        panel: null,
-        collection: null,
-        population: null,
-        commonCropName: null,
-        species: null,
-        genusSpecies: null,
-        subtaxa: null,
-        genusSpeciesSubtaxa: null,
-        taxonSynonyms: null,
-        taxonCommonNames: null,
-        biologicalStatus: null,
-        geneticNature: null,
-        holdingInstitute: null,
-        sources: null,
-        types: null,
-
-        facetFields: null,
-        sortBy: 'germplasmName',
-        sortOrder: null,
-        page: 1,
-        pageSize: 10,
-    };
-
-    const dataDiscoveryCriteria: DataDiscoveryCriteria = {
-        accessions: ['G_10', 'incisa', 'G_20'],
-        crops: ['cheery', 'prunus'],
-        facetFields: null,
-        germplasmLists: null,
-        observationVariableIds: null,
-        sources: ['URGI'],
-        types: null,
-        topSelectedTraitOntologyIds: null,
-
-        page: 1,
-        pageSize: 10
-    };
-
-
-    const gnpisService = jasmine.createSpyObj(
-        'GnpisService', [
-            'germplasmSearch'
-        ]
-    );
-    gnpisService.germplasmSearch.and.returnValue(of(germplasmSearchResult));
-
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            imports: [RouterTestingModule],
-            declarations: [GermplasmResultPageComponent, CardSectionComponent, LoadingSpinnerComponent],
-            providers: [
-                { provide: GnpisService, useValue: gnpisService }
-            ],
-            schemas: [NO_ERRORS_SCHEMA],
-        })
-            .compileComponents();
-
-        fixture = TestBed.createComponent(GermplasmResultPageComponent);
-        component = fixture.componentInstance;
-        component.criteriaFromForm$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils
-            .emptyCriteria());
-        component.germplasmSearchCriteria$ = new BehaviorSubject<GermplasmSearchCriteria>(DataDiscoveryCriteriaUtils
-            .emptyGermplasmSearchCriteria());
-
-        component.germplasmFacets$ = new BehaviorSubject<DataDiscoveryFacet[]>(facets);
-        fixture.detectChanges();
-    }));
-
-    it('should create', () => {
-        expect(component).toBeTruthy();
-    });
-
-    it('should fecth the germplasm', () => {
-        component.germplasmSearchCriteria$.next(criteria);
-        expect(component.localCriteria).toEqual(criteria);
-        expect(gnpisService.germplasmSearch).toHaveBeenCalledWith(criteria);
-        expect(component.germplasms).toEqual(germplasmSearchResult.result.data);
-
-    });
-
-    it('should get criteria information from data discovery criteria', () => {
-        component.criteriaFromForm$.next(dataDiscoveryCriteria);
-        fixture.detectChanges();
-
-        expect(component.localCriteria.commonCropName).toContain('cheery');
-        expect(component.localCriteria.commonCropName).toContain('prunus');
-        expect(component.localCriteria.commonCropName).toContain('cheery');
-        expect(component.localCriteria.genusSpecies).toContain('prunus');
-        expect(component.localCriteria.genusSpeciesSubtaxa).toContain('prunus');
-
-        expect(component.localCriteria.germplasmNames).toContain('G_10');
-        expect(component.localCriteria.accessionNumbers).toContain('incisa');
-        expect(component.localCriteria.synonyms).toContain('G_20');
-    });
-});
diff --git a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.ts b/frontend/src/app/germplasm-result-page/germplasm-result-page.component.ts
deleted file mode 100644
index a4b993e1b348a7702f8a8a7c623593f6a95203ed..0000000000000000000000000000000000000000
--- a/frontend/src/app/germplasm-result-page/germplasm-result-page.component.ts
+++ /dev/null
@@ -1,216 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import { GnpisService } from '../gnpis.service';
-import { Germplasm, GermplasmSearchCriteria } from '../models/gnpis.model';
-
-
-import { saveAs } from 'file-saver';
-import { ActivatedRoute } from '@angular/router';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryFacet,
-    DEFAULT_PAGE_SIZE,
-    MAX_RESULTS
-} from '../models/data-discovery.model';
-import { asArray } from '../utils';
-import { BehaviorSubject } from 'rxjs';
-
-@Component({
-    selector: 'faidare-germplasm-result-page',
-    templateUrl: './germplasm-result-page.component.html',
-    styleUrls: ['./germplasm-result-page.component.scss']
-})
-export class GermplasmResultPageComponent implements OnInit {
-
-
-    germplasms: Germplasm[];
-    localCriteria: GermplasmSearchCriteria = DataDiscoveryCriteriaUtils.emptyGermplasmSearchCriteria();
-
-    @Input() criteriaFromForm$: BehaviorSubject<DataDiscoveryCriteria>;
-    @Input() germplasmSearchCriteria$: BehaviorSubject<GermplasmSearchCriteria>;
-    @Input() germplasmFacets$: BehaviorSubject<DataDiscoveryFacet[]>;
-
-    headers: string[] = [
-        'germplasmName',
-        'accessionNumber',
-        'genusSpecies',
-        'instituteName',
-        'biologicalStatusOfAccessionCode',
-        'countryOfOriginCode'];
-    elementPerPage: number[] = [15, 20, 25];
-    loading: boolean;
-    overLimitSizeExport = false;
-    fieldSortState: object = {
-        germplasmName: null,
-        accessionNumber: null,
-        genusSpecies: null,
-        instituteName: null,
-        biologicalStatusOfAccessionCode: null
-    };
-
-    formatHeaders: { [key: string]: string } = {
-        'germplasmName': 'Germplasm name',
-        'accessionNumber': 'Accession number',
-        'genusSpecies': 'Genus species',
-        'instituteName': 'Institute name',
-        'biologicalStatusOfAccessionCode': 'Biological status',
-        'countryOfOriginCode': 'Country of origin'
-    };
-
-    pagination = {
-        startResult: 1,
-        endResult: DEFAULT_PAGE_SIZE,
-        totalResult: null,
-        currentPage: 0,
-        pageSize: DEFAULT_PAGE_SIZE,
-        totalPages: null,
-        maxResults: MAX_RESULTS
-    };
-
-    constructor(public service: GnpisService, private route: ActivatedRoute) {
-    }
-
-    ngOnInit() {
-
-        const queryParams = this.route.snapshot.queryParams;
-        this.reassignCriteriaFieldFromDataDiscoveryFields(queryParams);
-
-        this.criteriaFromForm$.subscribe(criteria => {
-            this.reassignCriteriaFieldFromDataDiscoveryFields(criteria);
-            this.germplasmSearchCriteria$.next(this.localCriteria);
-        });
-
-        this.germplasmSearchCriteria$
-            .subscribe(criteria => {
-                this.overLimitSizeExport = false;
-                this.localCriteria = criteria;
-                this.searchGermplasm(this.localCriteria);
-            });
-
-    }
-
-    searchGermplasm(criteria: GermplasmSearchCriteria) {
-        this.service.germplasmSearch(criteria)
-            .subscribe(({ metadata, facets, result }) => {
-                this.germplasms = result.data;
-                this.germplasmFacets$.next(facets);
-                DataDiscoveryCriteriaUtils.updatePagination(this.pagination, metadata.pagination);
-            });
-    }
-
-
-    reassignCriteriaFieldFromDataDiscoveryFields(criteria) {
-
-        this.localCriteria = {
-            ...this.localCriteria,
-            commonCropName: asArray(criteria.crops),
-            species: asArray(criteria.crops),
-            germplasmGenus: asArray(criteria.crops),
-            genusSpecies: asArray(criteria.crops),
-            subtaxa: asArray(criteria.crops),
-            genusSpeciesSubtaxa: asArray(criteria.crops),
-            taxonSynonyms: asArray(criteria.crops),
-            taxonCommonNames: asArray(criteria.crops),
-
-            panel: asArray(criteria.germplasmLists),
-            collection: asArray(criteria.germplasmLists),
-            population: asArray(criteria.germplasmLists),
-
-            germplasmNames: asArray(criteria.accessions),
-            accessionNumbers: asArray(criteria.accessions),
-            synonyms: asArray(criteria.accessions),
-
-            sources: asArray(criteria.sources)
-        };
-
-    }
-
-    exportPlantMaterial(criteria: GermplasmSearchCriteria) {
-        this.loading = true;
-        this.service.plantMaterialExport(criteria).subscribe(
-            result => {
-                if (result) {
-                    const blob = new Blob([result], { type: 'text/plain;charset=utf-8' });
-                    saveAs(blob, 'germplasm_gnpis.csv');
-                } else {
-                    this.overLimitSizeExport = true;
-                }
-                this.loading = false;
-            },
-            error => {
-                console.log(error);
-            });
-    }
-
-    exportMcpd(criteria: GermplasmSearchCriteria) {
-        this.loading = true;
-        this.service.mcpdExport(criteria).subscribe(
-            result => {
-                if (result) {
-                    const blob = new Blob([result], { type: 'text/plain;charset=utf-8' });
-                    saveAs(blob, 'germplasm_mcpd.csv');
-                } else {
-                    this.overLimitSizeExport = true;
-                }
-                this.loading = false;
-            },
-            error => {
-                console.log(error);
-            });
-    }
-
-    getTabField(tabField) {
-
-        this.switchSortOrder(tabField);
-        this.resetOtherFieldSort(tabField);
-
-        this.localCriteria.sortOrder = this.fieldSortState[tabField];
-
-        this.germplasmSearchCriteria$.next(this.localCriteria);
-
-        return tabField;
-    }
-
-    switchSortOrder(tabField) {
-        if (this.fieldSortState[tabField] === 'asc') {
-            this.localCriteria.sortBy = null;
-            return this.fieldSortState[tabField] = null;
-        }
-        if (this.fieldSortState[tabField] === 'desc') {
-            this.localCriteria.sortBy = tabField;
-            return this.fieldSortState[tabField] = 'asc';
-        }
-        if (!this.fieldSortState[tabField]) {
-            this.localCriteria.sortBy = tabField;
-            return this.fieldSortState[tabField] = 'desc';
-        }
-    }
-
-    resetOtherFieldSort(tabField) {
-        const otherHeaders = this.headers.filter(header => header !== tabField);
-        for (const header of otherHeaders) {
-            this.fieldSortState[header] = null;
-        }
-    }
-
-    resultCount() {
-        return Math.min(
-            this.pagination.totalResult,
-            MAX_RESULTS - DEFAULT_PAGE_SIZE
-        );
-    }
-
-    changePage(page: number) {
-        this.localCriteria.page = page - 1;
-        this.germplasmSearchCriteria$.next(this.localCriteria);
-    }
-
-    changeNbElementPerPage(pageSize: number) {
-        this.pagination.pageSize = pageSize;
-        this.elementPerPage = [10, 15, 20, 25];
-        this.elementPerPage = this.elementPerPage
-            .filter(otherPageSize => otherPageSize !== pageSize);
-        this.localCriteria.pageSize = pageSize;
-        this.germplasmSearchCriteria$.next(this.localCriteria);
-    }
-}
diff --git a/frontend/src/app/gnpis.service.spec.ts b/frontend/src/app/gnpis.service.spec.ts
deleted file mode 100644
index 6f82603c7dbd7595f0acaf3a4de3a29a9b6ca157..0000000000000000000000000000000000000000
--- a/frontend/src/app/gnpis.service.spec.ts
+++ /dev/null
@@ -1,303 +0,0 @@
-import { BASE_URL, GnpisService } from './gnpis.service';
-import { BrapiMetaData, BrapiResults } from './models/brapi.model';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoverySource
-} from './models/data-discovery.model';
-import {
-    HttpClientTestingModule,
-    HttpTestingController
-} from '@angular/common/http/testing';
-import { TestBed } from '@angular/core/testing';
-import {
-    Donor,
-    Germplasm,
-    GermplasmInstitute,
-    GermplasmSearchCriteria,
-    GermplasmSet,
-    Institute,
-    Site
-} from './models/gnpis.model';
-
-describe('GnpisService', () => {
-
-    const source1: DataDiscoverySource = {
-        '@id': 'id1',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'source 1',
-        'schema:url': 'http://source1.com',
-        'schema:image': 'image1',
-    };
-    const source2: DataDiscoverySource = {
-        '@id': 'id2',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'source 2',
-        'schema:url': 'http://source2.com',
-        'schema:image': 'image2',
-    };
-
-    const site: Site = {
-        latitude: null,
-        longitude: null,
-        siteId: '1',
-        siteName: 'Nantes',
-        siteType: null
-    };
-
-    const brapiInstitute: Institute = {
-        instituteName: 'urgi',
-        instituteCode: 'inra',
-        acronym: 'urgi',
-        organisation: 'inra',
-        instituteType: 'labo',
-        webSite: 'www.labo.fr',
-        address: '12',
-        logo: null
-    };
-
-    const germplasmInstitute: GermplasmInstitute = {
-        ...brapiInstitute,
-        institute: brapiInstitute,
-        accessionNumber: '12',
-        accessionCreationDate: '1993',
-        materialType: 'feuille',
-        collectors: null,
-        registrationYear: '1996',
-        deregistrationYear: '1912',
-        distributionStatus: null
-    };
-
-    const brapiDonor: Donor = {
-        donorInstitute: brapiInstitute,
-        donorGermplasmPUI: '12',
-        donorAccessionNumber: '12',
-        donorInstituteCode: 'urgi',
-        donationDate: null
-    };
-
-    const germplasmSet: GermplasmSet = {
-        germplasmCount: 12,
-        germplasmRef: null,
-        id: 12,
-        name: 'truc',
-        type: 'plan'
-    };
-
-    const germplasmTest: Germplasm = {
-        germplasmDbId: 'test',
-        defaultDisplayName: 'test',
-        accessionNumber: 'test',
-        germplasmName: 'test',
-        germplasmPUI: 'doi:1256',
-        pedigree: 'tree',
-        seedSource: 'inra',
-        synonyms: null,
-        commonCropName: null,
-        instituteCode: 'grc12',
-        instituteName: 'institut',
-        biologicalStatusOfAccessionCode: null,
-        countryOfOriginCode: null,
-        typeOfGermplasmStorageCode: null,
-        taxonIds: null,
-        genus: 'genre',
-        species: 'esp',
-        speciesAuthority: 'L',
-        subtaxa: null,
-        subtaxaAuthority: null,
-        donors: [brapiDonor],
-        acquisitionDate: null,
-        genusSpecies: null,
-        genusSpeciesSubtaxa: null,
-        taxonSynonyms: ['pomme', 'api'],
-        taxonCommonNames: ['pomme', 'api'],
-        taxonComment: null,
-        geneticNature: null,
-        comment: null,
-        photo: null,
-        holdingInstitute: brapiInstitute,
-        holdingGenbank: brapiInstitute,
-        presenceStatus: null,
-        children: null,
-        originSite: site,
-        collectingSite: null,
-        evaluationSites: null,
-        collector: germplasmInstitute,
-        breeder: germplasmInstitute,
-        distributors: [germplasmInstitute],
-        panel: [germplasmSet],
-        collection: [germplasmSet],
-        population: [germplasmSet],
-        'schema:includedInDataCatalog': null
-    };
-
-    const germplasmExportCriteria: GermplasmSearchCriteria = {
-        accessionNumbers: ['VCR010'],
-        germplasmDbIds: [],
-        germplasmGenus: [],
-        germplasmNames: [],
-        germplasmPUIs: [],
-        germplasmSpecies: [],
-
-        synonyms: null,
-        panel: null,
-        collection: null,
-        population: null,
-        commonCropName: null,
-        species: null,
-        genusSpecies: null,
-        subtaxa: null,
-        genusSpeciesSubtaxa: null,
-        taxonSynonyms: null,
-        taxonCommonNames: null,
-        biologicalStatus: null,
-        geneticNature: null,
-        holdingInstitute: null,
-        sources: null,
-        types: ['Germplasm'],
-
-        facetFields: null,
-        sortBy: null,
-        sortOrder: null,
-        page: 1,
-        pageSize: 10
-    };
-
-    const exportFile: string = '"DOI";"AccessionNumber";' +
-        '"AccessionName";"TaxonGroup";' +
-        '"HoldingInstitution";"LotName";' +
-        '"LotSynonym";' +
-        '"CollectionName";' +
-        '"CollectionType";' +
-        '"PanelName";' +
-        '"PanelSize"\n' +
-        '"https://germplasmdoi";"germplasm01";GermplasmTest;Pea;INRA-URGI;;;;;;';
-
-
-    let gnpisService: GnpisService;
-    let http: HttpTestingController;
-    beforeEach(() => {
-        TestBed.configureTestingModule({
-            imports: [HttpClientTestingModule],
-            providers: [HttpClientTestingModule]
-        });
-        gnpisService = TestBed.get(GnpisService);
-        http = TestBed.get(HttpTestingController);
-
-        const sources: BrapiResults<DataDiscoverySource> = {
-            result: {
-                data: [source1, source2]
-            }, metadata: {} as BrapiMetaData
-        };
-
-        const req = http.expectOne({
-            method: 'GET',
-            url: `${BASE_URL}/datadiscovery/sources`
-        });
-        req.flush(sources);
-
-    });
-
-
-    afterEach(() => http.verify());
-
-
-    it('should suggest with criteria', () => {
-        const expectedSuggestions = ['a', 'b', 'c'];
-        const field = 'foo';
-        const text = 'bar';
-        const criteria = { crops: ['d'] } as DataDiscoveryCriteria;
-        const fetchSize = 3;
-
-        gnpisService.suggest(field, fetchSize, text, criteria).subscribe(suggestions => {
-            expect(suggestions.length).toBe(3);
-            expect(suggestions).toBe(expectedSuggestions);
-        });
-
-        const req = http.expectOne({
-            url: `${BASE_URL}/datadiscovery/suggest?field=${field}&text=${text}&fetchSize=${fetchSize}`,
-            method: 'POST'
-        });
-        req.flush(expectedSuggestions);
-        expect(req.request.body).toBe(criteria);
-    });
-
-
-    afterAll(() => http.verify());
-
-    it('should fetch the germplasm', () => {
-        let fetchedGermplasm: Germplasm;
-        const germplasmDbId: string = germplasmTest.germplasmDbId;
-        gnpisService.getGermplasm({ id: germplasmDbId }).subscribe(response => {
-            fetchedGermplasm = response;
-        });
-        http.expectOne(`${BASE_URL}/germplasm?id=${germplasmDbId}`)
-            .flush(germplasmTest);
-
-        expect(fetchedGermplasm).toEqual(germplasmTest);
-    });
-
-    it('should search documents with criteria', () => {
-        const rawResult = {
-            metadata: {} as BrapiMetaData,
-            result: {
-                data: [{
-                    '@type': ['Germplasm'],
-                    '@id': 'urn',
-                    'schema:identifier': 'schema',
-                    'schema:name': 'doc_name',
-                    'schema:url': 'http://dco/url',
-                    'schema:description': 'description',
-                    'schema:includedInDataCatalog': source1['@id']
-                }, {
-                    '@type': ['Phenotyping Study'],
-                    '@id': 'urn',
-                    'schema:identifier': 'schema',
-                    'schema:name': 'doc_name',
-                    'schema:url': 'http://dco/url',
-                    'schema:description': 'description',
-                    'schema:includedInDataCatalog': source2['@id']
-                }]
-            },
-            facets: []
-        };
-
-        const criteria = { crops: ['d'] } as DataDiscoveryCriteria;
-
-        gnpisService.search(criteria).subscribe(result => {
-            expect(result.result.data.length).toBe(2);
-            expect(result.result.data[0]['schema:includedInDataCatalog']).toEqual(source1);
-            expect(result.result.data[1]['schema:includedInDataCatalog']).toEqual(source2);
-        });
-
-        const req = http.expectOne({
-            url: `${BASE_URL}/datadiscovery/search`,
-            method: 'POST'
-        });
-        req.flush(rawResult);
-
-        expect(req.request.body).toBe(criteria);
-    });
-
-    it('should fetch sources', () => {
-        gnpisService.sourceByURI$.subscribe(sourceByURI => {
-            expect(sourceByURI).toEqual({
-                'id1': source1,
-                'id2': source2
-            });
-        });
-    });
-
-    it('should export germplasm as PlantMaterial', () => {
-        gnpisService.plantMaterialExport(germplasmExportCriteria).subscribe(
-            plantMaterialExport => {
-                expect(plantMaterialExport).toEqual(exportFile);
-            }
-        );
-        const req = http.expectOne({
-            url: `${BASE_URL}/germplasm/germplasm-list-csv`,
-            method: 'POST'
-        });
-        req.flush(exportFile);
-    });
-})
-;
diff --git a/frontend/src/app/gnpis.service.ts b/frontend/src/app/gnpis.service.ts
deleted file mode 100644
index bf0b3b2a44fe9862498e028673e6562d80aa6dac..0000000000000000000000000000000000000000
--- a/frontend/src/app/gnpis.service.ts
+++ /dev/null
@@ -1,182 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Observable, ReplaySubject, zip } from 'rxjs';
-import { HttpClient } from '@angular/common/http';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryFacet,
-    DataDiscoveryResults,
-    DataDiscoverySource
-} from './models/data-discovery.model';
-import {
-    BrapiResults,
-    GermplasmCriteria,
-    GermplasmResults
-} from './models/brapi.model';
-import { map } from 'rxjs/operators';
-import { Germplasm, GermplasmSearchCriteria } from './models/gnpis.model';
-import { XrefResponse } from './models/xref.model';
-import { removeNullUndefined } from './utils';
-
-
-export const BASE_URL = 'faidare/v1';
-
-@Injectable({
-    providedIn: 'root'
-})
-export class GnpisService {
-    static URGI_SOURCE_URI = 'https://urgi.versailles.inra.fr';
-
-    sourceByURI$ = new ReplaySubject<Record<string, DataDiscoverySource>>(1);
-    sources$ = new ReplaySubject<DataDiscoverySource[]>(1);
-
-    constructor(private http: HttpClient) {
-        // Get data sources
-        this.http.get<BrapiResults<DataDiscoverySource>>(`${BASE_URL}/datadiscovery/sources`)
-            .pipe(map(response => response.result.data))
-            .subscribe(dataSources => {
-                // Index by URI
-                const sourceByURI = {};
-                for (const dataSource of dataSources) {
-                    sourceByURI[dataSource['@id']] = dataSource;
-                }
-                this.sources$.next(dataSources);
-                this.sourceByURI$.next(sourceByURI);
-            });
-    }
-
-    /**
-     * Fetch value suggestion for field.
-     * @param field the field on which to suggest values
-     * @param fetchSize number of values to fetch
-     * @param text search text that needs to match in field values
-     * @param criteria used to filter document before suggestion
-     * @return an observable of field values
-     */
-    suggest(
-        field: string,
-        fetchSize: number = null,
-        text: string = '',
-        criteria: DataDiscoveryCriteria = null
-    ): Observable<string[]> {
-        const params = removeNullUndefined({ field, text, fetchSize });
-        return this.http.post<string[]>(
-            `${BASE_URL}/datadiscovery/suggest`, criteria, { params }
-        );
-    }
-
-    /**
-     * Fetch data discovery documents by criteria
-     * @param criteria the criteria
-     * @return an observable of BrAPI results list of documents
-     */
-    search(
-        criteria: DataDiscoveryCriteria
-    ): Observable<DataDiscoveryResults> {
-        return this.mapSources( zip(
-            // Get source by URI
-            this.sourceByURI$,
-            // Get documents by criteria
-            this.http.post<any>(`${BASE_URL}/datadiscovery/search`, criteria)
-        ));
-    }
-
-
-    mapSources(httpResponse: Observable<any>) {
-        return httpResponse.pipe(map(([sourceByURI, response]) => {
-            // Extract BrAPI documents from result
-            const documents = response.result.data;
-
-            // Transform document to have the source details in place of the source URI
-            response.result.data = documents.map(document => {
-                const sourceURI = document['schema:includedInDataCatalog'];
-                document['schema:includedInDataCatalog'] = sourceByURI[sourceURI];
-                return document;
-            });
-            if (response.facets) {
-                this.getSourcesName(sourceByURI, response);
-            }
-            return response;
-        }));
-
-    }
-
-
-
-
-    /**
-     * Get germplasm by ID or PUI with data source (present in JSON-LD response)
-     * @param params containing Id or PUI
-     */
-    getGermplasm(params: { id?: string, pui?: string }): Observable<Germplasm> {
-        return this.http.get<Germplasm>(
-            `${BASE_URL}/germplasm`,
-            {
-                params: removeNullUndefined(params),
-                headers: { 'Accept': 'application/ld+json,application/json' }
-            }
-        );
-    }
-
-    germplasmSearch(criteria: GermplasmCriteria): Observable<GermplasmResults<Germplasm>> {
-
-        return this.mapSources(zip(
-            // Get source by URI
-            this.sourceByURI$,
-            // Get documents by criteria
-            this.http.post<GermplasmResults<Germplasm>>(`${BASE_URL}/germplasm/search`,
-                criteria,
-                { headers: { 'Accept': 'application/ld+json,application/json' } })));
-    }
-
-    /**
-     * Get data source by URI
-     */
-    getSource(sourceURI: string): Observable<DataDiscoverySource> {
-        return this.sourceByURI$.pipe(map(sourceByURI => sourceByURI[sourceURI]));
-    }
-
-    xref(xrefId: string): Observable<XrefResponse> {
-        return this.http.get<XrefResponse>(`${BASE_URL}/xref/documentbyfulltextid?linkedRessourcesID=${xrefId}`);
-    }
-
-    // TODO Change the service's response to return an object with the number of results and handle here if the number is over the limit
-    plantMaterialExport(criteria: GermplasmSearchCriteria): Observable<any> {
-        const requestOptions: Object = {
-            /* other options here */
-            responseType: 'text'
-        };
-        return this.http.post<any>(
-            `${BASE_URL}/germplasm/germplasm-list-csv`,
-            criteria,
-            requestOptions
-        );
-    }
-
-    // TODO Change the service's response to return an object with the number of results and handle here if the number is over the limit
-    mcpdExport(criteria: GermplasmSearchCriteria): Observable<any> {
-        const requestOptions: Object = {
-            /* other options here */
-            responseType: 'text'
-        };
-        return this.http.post<any>(
-            `${BASE_URL}/germplasm/germplasm-mcpd-csv`,
-            criteria,
-            requestOptions
-        );
-    }
-
-    getSourcesName(sourceByURI, response) {
-        response.facets = response.facets.map((facet: DataDiscoveryFacet) => {
-            facet.terms = facet.terms.map(term => {
-                if (facet.field === 'sources') {
-                    term.label = sourceByURI[term.term]['schema:name'];
-                } else {
-                    term.label = term.term;
-                }
-                return term;
-            });
-            return facet;
-        });
-    }
-
-}
diff --git a/frontend/src/app/loading-spinner/loading-spinner.component.scss b/frontend/src/app/loading-spinner/loading-spinner.component.scss
deleted file mode 100644
index 6a74cd33eee85c880e8a4737667e4dbd685fef19..0000000000000000000000000000000000000000
--- a/frontend/src/app/loading-spinner/loading-spinner.component.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-
-.loading {
-  display: inline-block;
-  animation: opacityPulse 1.5s infinite ease-in-out;
-
-  i {
-    color: black;
-    font-size: 2.2em;
-  }
-}
-
-$from: 0.3;
-$to: 1;
-@keyframes opacityPulse {
-  0% { opacity: $from; }
-  50% { opacity: $to; }
-  100% { opacity: $from; }
-}
diff --git a/frontend/src/app/loading-spinner/loading-spinner.component.ts b/frontend/src/app/loading-spinner/loading-spinner.component.ts
deleted file mode 100644
index c6852e4edfbea468f38cf64633acdb7a3481025f..0000000000000000000000000000000000000000
--- a/frontend/src/app/loading-spinner/loading-spinner.component.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import { ErrorInterceptorService } from '../error-interceptor.service';
-
-@Component({
-    selector: 'faidare-loading-spinner',
-    template: `
-        <div *ngIf="loading" class="loading">
-          <i class="fa fa-spin fa-spinner" title="Loading..."></i>
-        </div>
-    `,
-    styleUrls: ['./loading-spinner.component.scss']
-})
-export class LoadingSpinnerComponent implements OnInit {
-
-    @Input() loading: boolean;
-
-    constructor(private errorService: ErrorInterceptorService) {
-    }
-
-    ngOnInit(): void {
-        // Force loading stop when an error is intercepted
-        this.errorService.getErrors().subscribe(() => {
-            this.loading = false;
-        });
-    }
-}
diff --git a/frontend/src/app/map/map.component.html b/frontend/src/app/map/map.component.html
deleted file mode 100644
index ea33a10ff63831a86e76a3de4f17c02f4fa5ec26..0000000000000000000000000000000000000000
--- a/frontend/src/app/map/map.component.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<div id="map" class="rounded">
-</div>
-<div *ngIf="curatedLocationList.length > 0" id="maplegend">
-  <img src="assets/faidare/images/marker-icon-red.png" id="red"/>
-  <label for="red">Origin site</label>
-  <img src="assets/faidare/images/marker-icon-blue.png" id="blue"/>
-  <label for="blue">Collecting site</label>
-  <img src="assets/faidare/images/marker-icon-green.png" id="green"/>
-  <label for="green">Evaluation site</label>
-  <img src="assets/faidare/images/marker-icon-purple.png" id="purple"/>
-  <label for="purple">Multi-purpose site</label>
-</div>
diff --git a/frontend/src/app/map/map.component.scss b/frontend/src/app/map/map.component.scss
deleted file mode 100644
index 90a43b30e89be2c7c4720a92dc979cc11a5d19fa..0000000000000000000000000000000000000000
--- a/frontend/src/app/map/map.component.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-#map {
-  border: #0f6e9f solid 1px;
-  height: 400px;
-  width: 100%;
-}
-
-#maplegend {
-  margin: 10px;
-  font-size: 0.8em;
-}
-
-img {
-  margin-right: 5px;
-  margin-left: 5px;
-  height: 1.5em;
-  vertical-align: middle;
-}
diff --git a/frontend/src/app/map/map.component.spec.ts b/frontend/src/app/map/map.component.spec.ts
deleted file mode 100644
index 7a0b4df3ebca445b7820bddd6a4ac4bbfc87673a..0000000000000000000000000000000000000000
--- a/frontend/src/app/map/map.component.spec.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { MapComponent } from './map.component';
-import { BrapiLocation } from '../models/brapi.model';
-
-describe('MapComponent', () => {
-    let component: MapComponent;
-    let fixture: ComponentFixture<MapComponent>;
-    const location: BrapiLocation = {
-        locationDbId: '1',
-        latitude: 1,
-        longitude: 1,
-        altitude: 1,
-        instituteName: '',
-        instituteAddress: '',
-        countryName: '',
-        countryCode: '',
-        locationType: '',
-        abbreviation: '',
-        locationName: 'site1',
-        additionalInfo: {
-            Topography: '',
-            Slope: '',
-            Comment: '',
-            Exposure: '',
-            'Coordinates precision': '',
-            'Direction from city': '',
-            'Distance to city': '',
-            'Environment type': '',
-            'Geographical location': '',
-            'Site status': ''
-        }
-    };
-    const locations: BrapiLocation[] = [];
-    locations.push(location);
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            declarations: [MapComponent]
-        })
-            .compileComponents();
-    }));
-
-    beforeEach(() => {
-        fixture = TestBed.createComponent(MapComponent);
-        component = fixture.componentInstance;
-    });
-
-    it('should create component', () => {
-        component.locations = locations;
-        fixture.detectChanges();
-        expect(component).toBeTruthy();
-    });
-
-    it('should display map', () => {
-        component.locations = locations;
-        fixture.detectChanges();
-        const element = fixture.nativeElement;
-        expect(element.querySelector('#map')).toBeTruthy();
-    });
-
-    it('should display map legend', () => {
-        component.locations = locations;
-        fixture.detectChanges();
-        const element = fixture.nativeElement;
-        expect(element.querySelector('#maplegend')).toBeTruthy();
-    });
-});
diff --git a/frontend/src/app/map/map.component.ts b/frontend/src/app/map/map.component.ts
deleted file mode 100644
index 8802c8514ce33d3386a90b7a9ec78ee2902922f4..0000000000000000000000000000000000000000
--- a/frontend/src/app/map/map.component.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import * as L from 'leaflet';
-import { MarkerClusterGroup } from 'leaflet.markercluster/src';
-import { BrapiLocation } from '../models/brapi.model';
-
-@Component({
-    selector: 'faidare-map',
-    templateUrl: './map.component.html',
-    styleUrls: ['./map.component.scss']
-})
-export class MapComponent implements OnInit {
-
-    @Input() locations: BrapiLocation[];
-    curatedLocationList: BrapiLocation[] = [];
-
-    constructor() {
-    }
-
-    ngOnInit() {
-
-        this.removeEmptyLocations(this.locations);
-        if (this.curatedLocationList.length > 0) {
-            const map = L.map('map');
-
-            // initialize map centered on the first site
-            const firstLocation: BrapiLocation = this.curatedLocationList[0];
-            if (firstLocation) {
-                map.setView([firstLocation.latitude, firstLocation.longitude], 5);
-            }
-
-            L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
-                attribution: 'Tiles &copy; Esri &mdash; Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, ' +
-                    'Esri China (Hong Kong), Esri (Thailand), TomTom, 2012'
-            }).addTo(map);
-
-            // add markers for all locations using markercluster plugin
-            const markers = new MarkerClusterGroup();
-            const mapMarkers = [];
-            for (const location of this.curatedLocationList) {
-                const icon = L.icon({
-                    iconUrl: this.getMarkerIconUrl(location),
-                    iconAnchor: [12, 41], // point of the icon which will correspond to marker's location
-                });
-                const popupText = `
-                  <b>${location.locationName}</b><br/>
-                  ${location.locationType}<br/>
-                  <a href="sites/${location.locationDbId.replace(/=/g, '%3D')}">Details</a>
-                `;
-                const marker = L.marker(
-                    [location.latitude, location.longitude],
-                    { icon: icon }
-                );
-                markers.addLayer(
-                    marker.bindPopup(popupText)
-                );
-                mapMarkers.push(marker);
-            }
-            const initialZoom = map.getZoom();
-
-
-            map.fitBounds(L.featureGroup(mapMarkers).getBounds());
-            const markerZoom = map.getZoom();
-
-            setTimeout(() => {
-                map.setZoom(Math.min(initialZoom, markerZoom));
-                map.addLayer(markers);
-            }
-                , 100);
-
-        } else {
-            L.DomUtil.get('map').remove();
-        }
-    }
-
-
-    getMarkerIconUrl(site: BrapiLocation): string {
-        if (site.locationType === 'Origin site') {
-            return 'assets/faidare/images/marker-icon-red.png';
-        }
-        if (site.locationType === 'Collecting site') {
-            return 'assets/faidare/images/marker-icon-blue.png';
-        }
-        if (site.locationType === 'Evaluation site') {
-            return 'assets/faidare/images/marker-icon-green.png';
-        }
-        return 'assets/faidare/images/marker-icon-purple.png';
-    }
-
-    removeEmptyLocations(locations: BrapiLocation[]) {
-        for (const location of locations) {
-            if (location && location.latitude && location.longitude) {
-                this.curatedLocationList.push(location);
-            }
-        }
-    }
-}
diff --git a/frontend/src/app/markdown-page/markdown-page.component.html b/frontend/src/app/markdown-page/markdown-page.component.html
deleted file mode 100644
index a788f3001dfee82c050fbbea92b5ee19d87f9753..0000000000000000000000000000000000000000
--- a/frontend/src/app/markdown-page/markdown-page.component.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<markdown [src]="mdFile" lineNumbers="true" (error)="onError($event)"
-          (load)="onLoad($event)"></markdown>
diff --git a/frontend/src/app/markdown-page/markdown-page.component.scss b/frontend/src/app/markdown-page/markdown-page.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/frontend/src/app/markdown-page/markdown-page.component.spec.ts b/frontend/src/app/markdown-page/markdown-page.component.spec.ts
deleted file mode 100644
index 891bf14f06bc977057729dc1d6a9b486a5cd93e6..0000000000000000000000000000000000000000
--- a/frontend/src/app/markdown-page/markdown-page.component.spec.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
-
-import { MarkdownPageComponent } from './markdown-page.component';
-import { ActivatedRoute } from '@angular/router';
-import { environment } from '../../environments/environment';
-import { of } from 'rxjs';
-
-describe('MarkdownPageComponent', () => {
-    let component: MarkdownPageComponent;
-    let fixture: ComponentFixture<MarkdownPageComponent>;
-    const route = ({ data: of({ mdFile: environment.helpMdFile }) } as any) as ActivatedRoute;
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            declarations: [ MarkdownPageComponent ],
-            providers: [{ provide: ActivatedRoute, useValue: route }],
-            schemas: [NO_ERRORS_SCHEMA]
-        })
-            .compileComponents();
-    }));
-
-    beforeEach(() => {
-        fixture = TestBed.createComponent(MarkdownPageComponent);
-        component = fixture.componentInstance;
-        fixture.detectChanges();
-    });
-
-    it('should create', () => {
-        expect(component).toBeTruthy();
-        expect(component.mdFile).toEqual('assets/HELP.md');
-    });
-});
diff --git a/frontend/src/app/markdown-page/markdown-page.component.ts b/frontend/src/app/markdown-page/markdown-page.component.ts
deleted file mode 100644
index 232d1f10adc3773530a50566d147658a24560850..0000000000000000000000000000000000000000
--- a/frontend/src/app/markdown-page/markdown-page.component.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { ActivatedRoute } from '@angular/router';
-
-@Component({
-    selector: 'faidare-markdown',
-    templateUrl: './markdown-page.component.html',
-    styleUrls: ['./markdown-page.component.scss']
-})
-export class MarkdownPageComponent implements OnInit {
-
-    mdFile = '';
-
-    constructor(private route: ActivatedRoute) {
-    }
-
-    ngOnInit() {
-        this.route.data.subscribe(
-            value => this.mdFile = value.mdFile);
-    }
-
-    onLoad(e: any) {
-        // console.log('Into onLoad');
-        // console.log(e);
-    }
-
-    onError(e: any) {
-        console.log('Got error', e);
-    }
-
-}
diff --git a/frontend/src/app/models/brapi.model.ts b/frontend/src/app/models/brapi.model.ts
deleted file mode 100644
index 27a75f05e8c6ead1870c4f886311ddd271e5f82c..0000000000000000000000000000000000000000
--- a/frontend/src/app/models/brapi.model.ts
+++ /dev/null
@@ -1,323 +0,0 @@
-import * as schema from './schema.org.model';
-import { DataDiscoveryFacet } from './data-discovery.model';
-
-export interface GermplasmCriteria {
-    accessionNumbers: string[];
-    germplasmDbIds: string[];
-    germplasmGenus: string[];
-    germplasmNames: string[];
-    germplasmPUIs: string[];
-    germplasmSpecies: string[];
-    page: number;
-    pageSize: number;
-}
-
-export const DEFAULT_PAGE_SIZE = 10;
-
-export class BrapiCriteriaUtils {
-    static emptyCriteria(): GermplasmCriteria {
-        return {
-            accessionNumbers: null,
-            germplasmDbIds: null,
-            germplasmGenus: null,
-            germplasmNames: null,
-            germplasmPUIs: null,
-            germplasmSpecies: null,
-            page: 0,
-            pageSize: DEFAULT_PAGE_SIZE
-        };
-    }
-}
-
-export interface BrapiMetaData {
-    pagination: {
-        pageSize: number;
-        currentPage: number;
-        totalCount: number;
-        totalPages: number;
-    };
-}
-
-/**
- * BrAPI single response
- */
-export interface BrapiResult<T> {
-    metadata: BrapiMetaData;
-    result: T;
-}
-
-export interface GermplasmResult<T> {
-    metadata: BrapiMetaData;
-    facets: DataDiscoveryFacet[];
-    result: T;
-}
-
-/**
- * BrAPI list response
- */
-export type BrapiResults<T> = BrapiResult<{
-    data: T[];
-}>;
-
-export type GermplasmResults<T> = GermplasmResult<{
-    data: T[];
-}>;
-
-
-interface BrapiHasDocumentationURL {
-    documentationURL?: string;
-}
-
-export interface BrapiStudy extends BrapiHasDocumentationURL, schema.Dataset {
-    studyDbId: string;
-    studyType: string;
-    studyName: string;
-    studyDescription: string;
-    seasons: string[];
-    startDate: string;
-    endDate: string;
-    active: boolean;
-    programDbId: string;
-    programName: string;
-    trialDbIds: string[];
-    location: BrapiLocation;
-    locationDbId: string;
-    locationName: string;
-    contacts: BrapiContacts[];
-    additionalInfo: BrapiAdditionalInfo;
-    dataLinks: {
-        name: string;
-        type: string;
-        url: string;
-    }[];
-}
-
-
-export interface BrapiContacts {
-    contactDbId: string;
-    name: string;
-    email: string;
-    type: string;
-    institutionName: string;
-}
-
-
-export interface BrapiLocation extends BrapiHasDocumentationURL, schema.Dataset {
-    locationDbId: string;
-    locationName: string;
-    locationType: string;
-    abbreviation?: string;
-    countryCode?: string;
-    countryName?: string;
-    instituteAddress?: string;
-    instituteName?: string;
-    altitude?: number;
-    latitude: number;
-    longitude: number;
-    additionalInfo?: BrapiAdditionalInfo;
-}
-
-
-export interface BrapiAdditionalInfo {
-    [key: string]: string;
-}
-
-
-export interface BrapiObservationVariable extends BrapiHasDocumentationURL {
-    observationVariableDbId: string;
-    contextOfUse: string[];
-    institution: string;
-    crop: string;
-    name: string;
-    ontologyDbId: string;
-    ontologyName: string;
-    synonyms: string[];
-    language: string;
-    trait: {
-        traitDbId: string;
-        name: string;
-        description: string;
-    };
-}
-
-
-export interface BrapiTrial extends BrapiHasDocumentationURL {
-    trialDbId: string;
-    trialName: string;
-    trialType: string;
-    active: boolean;
-    studies: {
-        studyDbId: string;
-        studyName: string;
-    }[];
-}
-
-export interface BrapiGermplasm extends BrapiHasDocumentationURL, schema.Dataset {
-    germplasmDbId: string;
-    defaultDisplayName: string;
-    accessionNumber: string;
-    germplasmName: string;
-    germplasmPUI: string;
-    pedigree: string;
-    seedSource: string;
-    synonyms: string[];
-    commonCropName: string;
-    instituteCode: string;
-    instituteName: string;
-    biologicalStatusOfAccessionCode: string;
-    countryOfOriginCode: string;
-    typeOfGermplasmStorageCode: string[];
-    taxonIds: BrapiTaxonIds[];
-    genus: string;
-    species: string;
-    speciesAuthority: string;
-    subtaxa: string;
-    subtaxaAuthority: string;
-    donors: BrapiDonor[];
-    acquisitionDate: string;
-}
-
-export interface BrapiGermplasmMcpd extends BrapiHasDocumentationURL {
-    groupId: string;
-    accessionNames: string[];
-    accessionNumber: string;
-    acquisitionDate: string;
-    acquisitionSourceCode: string;
-    alternateIDs: string[];
-    ancestralData: string;
-    biologicalStatusOfAccessionCode: string;
-    breedingInstitutes: BrapiInstitute;
-    collectingInfo: {
-        collectingDate: string;
-        collectingInstitutes: BrapiInstitute;
-        collectingMissionIdentifier: string;
-        collectingNumber: string;
-        collectors: string;
-        materialType: string;
-        collectingSite: BrapiCollectingSite
-    };
-    commonCropName: string;
-    countryOfOriginCode: string;
-    donorInfo: {
-        donorAccessionNumber: string;
-        donorInstitute: BrapiInstitute;
-        donationDate: string;
-    };
-    genus: string;
-    germplasmDbId: string;
-    germplasmPUI: string;
-    instituteCode: string;
-    mlsStatus: string;
-    remarks: string;
-    safetyDuplicateInstitutes: {
-        instituteCode: string;
-        instituteName: string;
-    }[];
-    species: string;
-    speciesAuthority: string;
-    storageTypeCodes: string[];
-    subtaxon: string;
-    subtaxonAuthority: string;
-    breederAccessionNumber: string;
-    breedingCreationYear: string;
-    catalogRegistrationYear: string;
-    catalogDeregistrationYear: string;
-    originLocationDbId: string;
-    originLocationName: string;
-    holdingInstitute: BrapiInstitute;
-    holdingGenbank: BrapiInstitute;
-    geneticNature: string;
-    presenceStatus: string;
-    distributorInfos: {
-        institute: BrapiInstitute;
-        accessionNumber: string;
-        distrubutionStatus: string;
-    };
-}
-
-export interface BrapiInstitute {
-    instituteName: string;
-    instituteCode: string;
-    acronym: string;
-    organisation: string;
-    instituteType: string;
-    webSite: string;
-    instituteAddress: string;
-    logo: string;
-}
-
-export interface BrapiCollectingSite {
-    locationDbId: string;
-    locationName: string;
-    coordinateUncertainty: string;
-    elevation: string;
-    georeferencingMethod: string;
-    latitudeDecimal: string;
-    latitudeDegrees: string;
-    locationDescription: string;
-    longitudeDecimal: string;
-    longitudeDegrees: string;
-    spatialReferenceSystem: string;
-}
-
-
-export interface BrapiTaxonIds {
-    sourceName: string;
-    taxonId: string;
-    url: string;
-}
-
-export interface BrapiDonor {
-    donorGermplasmPUI: string;
-    donorAccessionNumber: string;
-    donorInstituteCode: string;
-    donationDate: number;
-}
-
-export interface BrapiGermplasmPedigree {
-    germplasmDbId: string;
-    defaultDisplayName: string;
-    pedigree: string;
-    crossingPlan: string;
-    crossingYear: string;
-    familyCode: string;
-    parent1DbId: string;
-    parent1Name: string;
-    parent1Type: string;
-    parent2DbId: string;
-    parent2Name: string;
-    parent2Type: string;
-    siblings: BrapiSibling[];
-}
-
-export interface BrapiSibling {
-    germplasmDbId: string;
-    defaultDisplayName: string;
-}
-
-export interface BrapiGermplasmProgeny {
-    germplasmDbId: string;
-    defaultDisplayName: string;
-    progeny: BrapiProgeny[];
-}
-
-export interface BrapiProgeny {
-    germplasmDbId: string;
-    defaultDisplayName: string;
-    parentType: string;
-
-}
-
-
-export interface BrapiGermplasmAttributes {
-    germplasmDbId: string;
-    data: BrapiAttributeData[];
-}
-
-export interface BrapiAttributeData {
-    attributeDbId: string;
-    attributeName: string;
-    attributeCode: string;
-    value: string;
-    determinedDate: string;
-}
diff --git a/frontend/src/app/models/data-discovery.model.ts b/frontend/src/app/models/data-discovery.model.ts
deleted file mode 100644
index 63958fcc13fe2cd1d6719239767fe13e0803baa6..0000000000000000000000000000000000000000
--- a/frontend/src/app/models/data-discovery.model.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-import { BrapiResults } from './brapi.model';
-import { Params } from '@angular/router';
-import { asArray } from '../utils';
-import * as schema from './schema.org.model';
-import { GermplasmSearchCriteria } from './gnpis.model';
-
-
-export const MAX_RESULTS = 10000;
-export const DEFAULT_PAGE_SIZE = 10;
-
-export interface DataDiscoveryCriteria {
-    accessions: string[];
-    crops: string[];
-    facetFields: string[];
-    germplasmLists: string[];
-    observationVariableIds: string[];
-    sources: string[];
-    types: string[];
-
-    /**
-     * Used to store the top selected node ids from the trait ontology widget
-     */
-    topSelectedTraitOntologyIds: string[];
-
-    page: number;
-    pageSize: number;
-}
-
-export class DataDiscoveryCriteriaUtils {
-    static emptyCriteria(): DataDiscoveryCriteria {
-        return {
-            accessions: null,
-            crops: null,
-            facetFields: ['types', 'sources'],
-            germplasmLists: null,
-            observationVariableIds: null,
-            topSelectedTraitOntologyIds: null,
-            sources: null,
-            types: null,
-
-            page: 0,
-            pageSize: DEFAULT_PAGE_SIZE
-        };
-    }
-
-    static emptyGermplasmSearchCriteria(): GermplasmSearchCriteria {
-        return {
-            accessionNumbers: null,
-            germplasmDbIds: null,
-            germplasmGenus: null,
-            germplasmNames: null,
-            germplasmPUIs: null,
-            germplasmSpecies: null,
-            holdingInstitute: null,
-            synonyms: null,
-            panel: null,
-            collection: null,
-            population: null,
-            commonCropName: null,
-            species: null,
-            genusSpecies: null,
-            subtaxa: null,
-            genusSpeciesSubtaxa: null,
-            taxonSynonyms: null,
-            taxonCommonNames: null,
-            biologicalStatus: null,
-            geneticNature: null,
-            sources: null,
-            types: ['Germplasm'],
-
-            facetFields: ['sources', 'holdingInstitute',
-                'biologicalStatus', 'geneticNature', 'country'],
-            sortBy: null,
-            sortOrder: null,
-            page: 0,
-            pageSize: 10,
-        };
-    }
-
-    static checkCriteriaIsEmpty(criteria): boolean {
-        for (const field of Object.keys(criteria)) {
-            if (field === 'facetFields') {
-                // Ignore facet fields criteria
-                continue;
-            }
-            if (criteria[field] && criteria[field].length) {
-                return false;
-            }
-
-        }
-        return true;
-    }
-
-    static fromQueryParams(queryParams: Params): DataDiscoveryCriteria {
-        return {
-            ...DataDiscoveryCriteriaUtils.emptyCriteria(),
-
-            crops: asArray(queryParams.crops),
-            germplasmLists: asArray(queryParams.germplasmLists),
-            accessions: asArray(queryParams.accessions),
-            sources: asArray(queryParams.sources),
-            types: asArray(queryParams.types),
-
-            // The URL should only contain top selected trait ontology node ids
-            topSelectedTraitOntologyIds: asArray(queryParams.observationVariableIds),
-
-            page: queryParams.page - 1 || 0
-        };
-    }
-
-    static toQueryParams(newCriteria: DataDiscoveryCriteria) {
-        return {
-            crops: newCriteria.crops,
-            accessions: newCriteria.accessions,
-            germplasmLists: newCriteria.germplasmLists,
-            sources: newCriteria.sources,
-            types: newCriteria.types,
-
-            // The URL should only contain top selected trait ontology node ids
-            observationVariableIds: newCriteria.topSelectedTraitOntologyIds,
-
-            page: newCriteria.page + 1
-        };
-    }
-
-    static updatePagination(previousPagination, { currentPage, pageSize, totalCount, totalPages }) {
-        previousPagination.currentPage = currentPage;
-        previousPagination.pageSize = pageSize;
-        previousPagination.totalPages = totalPages;
-        previousPagination.startResult = pageSize * currentPage + 1;
-        previousPagination.endResult = previousPagination.startResult + pageSize - 1;
-        previousPagination.totalResult = totalCount;
-    }
-}
-
-export type DataDiscoverySource = schema.DataCatalog;
-
-export interface DataDiscoveryDocument extends schema.Dataset {
-    ['@id']: string;
-    ['@type']: DataDiscoveryType[];
-    ['schema:identifier']: string;
-    ['schema:name']: string;
-    ['schema:url']: string;
-    ['schema:description']: string;
-    ['schema:includedInDataCatalog']: DataDiscoverySource;
-}
-
-// TODO: use enum
-export type DataDiscoveryType = 'Germplasm' | 'Phenotyping Study' | 'Genotyping Study';
-
-export interface DataDiscoveryResults extends BrapiResults<DataDiscoveryDocument> {
-    facets: DataDiscoveryFacet[];
-}
-
-export interface DataDiscoveryFacet {
-    field: string;
-    terms: {
-        term: string;
-        label: string;
-        count: number;
-    }[];
-}
diff --git a/frontend/src/app/models/gnpis.model.ts b/frontend/src/app/models/gnpis.model.ts
deleted file mode 100644
index 8e9ebeb989ea827de823db84753534efa851154b..0000000000000000000000000000000000000000
--- a/frontend/src/app/models/gnpis.model.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-import { BrapiDonor, BrapiGermplasm } from './brapi.model';
-
-
-export interface GermplasmSearchCriteria {
-    accessionNumbers: string[];
-    germplasmDbIds: string[];
-    germplasmGenus: string[];
-    germplasmNames: string[];
-    germplasmPUIs: string[];
-    germplasmSpecies: string[];
-
-    synonyms: string[];
-    panel: string[];
-    collection: string[];
-    population: string[];
-    commonCropName: string[];
-    species: string[];
-    genusSpecies: string[];
-    subtaxa: string[];
-    genusSpeciesSubtaxa: string[];
-    taxonSynonyms: string[];
-    taxonCommonNames: string[];
-    biologicalStatus: string[];
-    geneticNature: string[];
-    holdingInstitute: string[];
-    sources: string[];
-    types: string[];
-
-    facetFields: string[];
-    sortBy: string;
-    sortOrder: string;
-    page: number;
-    pageSize: number;
-}
-
-
-export interface Germplasm extends BrapiGermplasm {
-    genusSpecies: string;
-    genusSpeciesSubtaxa: string;
-    taxonSynonyms: string[];
-    taxonCommonNames: string[];
-    taxonComment: string;
-    geneticNature: string;
-    comment: string;
-    photo: Photo;
-    holdingInstitute: Institute;
-    holdingGenbank: Institute;
-    presenceStatus: string;
-    children: Children[];
-    originSite: Site;
-    collectingSite: Site;
-    evaluationSites: Site[];
-    collector: GermplasmInstitute;
-    breeder: GermplasmInstitute;
-    donors: Donor[];
-    distributors: GermplasmInstitute[];
-    panel: GermplasmSet[];
-    collection: GermplasmSet[];
-    population: GermplasmSet[];
-    'schema:includedInDataCatalog': any;
-}
-
-
-/* export interface GermplasmMcpd extends  BrapiGermplasm {
-    mlsStatus: string;
-} */
-
-
-export interface Site {
-    latitude: number;
-    longitude: number;
-    siteId: string;
-    siteName: string;
-    siteType: string;
-}
-
-export interface Institute {
-    instituteName: string;
-    instituteCode: string;
-    acronym: string;
-    organisation: string;
-    instituteType: string;
-    webSite: string;
-    address: string;
-    logo: string;
-}
-
-export interface GermplasmInstitute extends Institute {
-    institute: Institute;
-    accessionNumber: string;
-    accessionCreationDate: string;
-    materialType: string;
-    collectors: string;
-    registrationYear: string;
-    deregistrationYear: string;
-    distributionStatus?: string;
-}
-
-export interface Photo {
-    copyright: string;
-    description: string;
-    file: string;
-    photoName: string;
-    thumbnailFile: string;
-
-}
-
-export interface Children {
-    firstParentName: string;
-    firstParentPUI: string;
-    secondParentName: string;
-    secondParentPUI: string;
-    sibblings: {
-        name: string;
-        pui: string;
-    }[];
-
-}
-
-export interface Donor extends BrapiDonor {
-    donorInstitute: Institute;
-}
-
-
-export interface GermplasmSet {
-    id: number;
-    name: string;
-    type: string;
-    germplasmCount: number;
-    germplasmRef: {
-        pui: string;
-        name: string;
-    };
-
-
-}
diff --git a/frontend/src/app/models/schema.org.model.ts b/frontend/src/app/models/schema.org.model.ts
deleted file mode 100644
index 982457cf3998ce7ecb34e0ba614856cd3a0362d1..0000000000000000000000000000000000000000
--- a/frontend/src/app/models/schema.org.model.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Basic JSON-LD object (non exhaustive list of properties)
- */
-export interface JsonLD {
-    ['@context']?: any;
-    ['@id']?: string;
-    ['@type']?: string | string[];
-}
-
-/**
- * https://schema.org/DataCatalog
- */
-export interface DataCatalog extends JsonLD {
-    ['@id']: string;
-    ['@type']: ['schema:DataCatalog'];
-    ['schema:name']: string;
-    ['schema:url']: string;
-    ['schema:image']: string;
-}
-
-/**
- * https://schema.org/Dataset
- */
-export interface Dataset extends JsonLD {
-    // Identifier
-    ['schema:identifier']?: string;
-
-    // Display name
-    ['schema:name']?: string;
-
-    // Equivalent to BrAPI 'documentationURL'
-    ['schema:url']?: string;
-
-    // Source data catalog (string URI or data catalog object)
-    ['schema:includedInDataCatalog']?: string | DataCatalog;
-}
-
diff --git a/frontend/src/app/models/xref.model.ts b/frontend/src/app/models/xref.model.ts
deleted file mode 100644
index c204f787c40384df66d385d62c03eaa5bfdfa4ee..0000000000000000000000000000000000000000
--- a/frontend/src/app/models/xref.model.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export interface XrefModel {
-
-    url: string;
-    description: string;
-    database_name: string;
-    entry_type: string;
-    db_version: string;
-    name: string;
-
-}
-
-export type XrefResponse = XrefModel[];
diff --git a/frontend/src/app/navbar/navbar.component.html b/frontend/src/app/navbar/navbar.component.html
deleted file mode 100644
index bbafeb37306337841a7da56d215b34de6a2f179b..0000000000000000000000000000000000000000
--- a/frontend/src/app/navbar/navbar.component.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<nav class="navbar fixed-top navbar-expand-md navbar-dark py-0 mb-4">
-  <div class="container px-0">
-    <a class="navbar-brand d-flex align-items-center mr-0 px-2" routerLink="/">
-      <img src="{{ navbar.logo }}" alt="{{ navbar.name }} logo" title="{{ navbar.title }}" height="60px"/>
-    </a>
-    <button class="navbar-toggler" type="button" (click)="toggleNavbar()">
-      <span class="fa fa-bars"></span>
-    </button>
-    <div id="navbar" class="collapse navbar-collapse" [class.collapse]="navbarCollapsed">
-      <ul class="navbar-nav mr-auto">
-        <li class="nav-item" *ngFor="let link of navbar.links">
-
-          <!-- Simple link -->
-          <div class="mr-2" *ngIf="!link.subMenu">
-            <a class="nav-link d-flex align-items-center"
-               [href]="link.url" target="_blank">{{ link.label }}</a>
-          </div>
-
-          <!-- OR Dropdown button -->
-          <div class="mr-2" *ngIf="link.subMenu" class="dropdown-container" ngbDropdown>
-            <!-- Toggle button -->
-            <a class="nav-link d-flex align-items-center dropdown-toggle" ngbDropdownToggle
-               role="button"
-               aria-haspopup="true"
-               aria-expanded="false">{{ link.label }}</a>
-            <!-- Items -->
-            <div class="dropdown-menu" ngbDropdownMenu>
-              <div *ngFor="let subItem of link.subMenu">
-                <a class="dropdown-item"
-                   target="_blank" [href]="subItem.url">{{ subItem.label }}</a>
-              </div>
-            </div>
-          </div>
-        </li>
-
-        <!-- Documentation -->
-        <li class="nav-item">
-          <div class="mr-2" class="dropdown-container" ngbDropdown>
-            <a class="nav-link d-flex align-items-center dropdown-toggle" ngbDropdownToggle
-               role="button"
-               aria-haspopup="true"
-               aria-expanded="false">More...</a>
-            <div class="dropdown-menu" ngbDropdownMenu>
-              <!-- About link -->
-              <a class="dropdown-item" routerLink="/about" routerLinkActive="true" title="About">About</a>
-              <!-- Join us link -->
-              <a class="dropdown-item" routerLink="/join" routerLinkActive="true" title="Join us">Join us</a>
-              <!-- Legal mentions link -->
-              <a class="dropdown-item" routerLink="/legal" routerLinkActive="true" title="Terms of use">Terms of use</a>
-              <!-- Help link -->
-              <a class="dropdown-item" routerLink="/help" routerLinkActive="true" title="Help">Help</a>
-            </div>
-          </div>
-        </li>
-      </ul>
-    </div>
-    <a class="navbar-brand d-flex align-items-center"
-       [href]="navbar.contributor.url" target="_blank">
-      <img src="{{ navbar.contributor.logo }}" alt="{{ navbar.contributor.name }} logo" title="{{ navbar.contributor.name }}" height="60px"/>
-    </a>
-    <div>
-      <!--<a *ngIf="displayBackButton"
-         [routerLink]="['/']"
-         [queryParams]="previousQueryParam">
-        <button type="button" class="btn btn-secondary">
-          < Back to form
-        </button>
-      </a>-->
-    </div>
-
-  </div>
-</nav>
diff --git a/frontend/src/app/navbar/navbar.component.scss b/frontend/src/app/navbar/navbar.component.scss
deleted file mode 100644
index 7319121ee7beddf4da19188ebf584f0999fa665e..0000000000000000000000000000000000000000
--- a/frontend/src/app/navbar/navbar.component.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-@import "theme";
-
-.navbar {
-  background-color: $theme-navbar-bg-color;
-  /*background-image: linear-gradient($theme-navbar-bg-color, #D3D3D3, $theme-navbar-bg-color);*/
-}
-
-.navbar-toggler {
-  color: $theme-navbar-color;
-  border-color: $theme-navbar-color;
-  font-size: 1.5rem;
-  line-height: 1.5rem;
-}
-
-.navbar .navbar-nav .nav-link, .navbar .navbar-brand {
-  color: $theme-navbar-color;
-  height: $theme-navbar-height;
-  text-decoration: none;
-
-  &:hover {
-    color: $theme-navbar-hover-color;
-    background-color: $theme-navbar-hover-bg-color;
-  }
-}
-
-.dropdown-container {
-  position: relative;
-}
-
diff --git a/frontend/src/app/navbar/navbar.component.spec.ts b/frontend/src/app/navbar/navbar.component.spec.ts
deleted file mode 100644
index 3a52062b227d1232c61d5d24dc941ffa9d7c9838..0000000000000000000000000000000000000000
--- a/frontend/src/app/navbar/navbar.component.spec.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { NavbarComponent } from './navbar.component';
-import { ComponentTester } from 'ngx-speculoos';
-import { DataDiscoverySource } from '../models/data-discovery.model';
-import { of } from 'rxjs';
-import { GnpisService } from '../gnpis.service';
-
-class NavbarComponentTester extends ComponentTester<NavbarComponent> {
-    constructor() {
-        super(NavbarComponent);
-    }
-
-    get navBar() {
-        return this.element('#navbar');
-    }
-
-    get toggler() {
-        return this.button('button');
-    }
-
-    get links() {
-        return this.elements('li');
-    }
-
-    get firstLink() {
-        return this.element('li').element('a');
-    }
-
-    get providerLinks() {
-        return this.links[1].elements('a');
-    }
-
-    get logos() {
-        return this.elements('img');
-    }
-}
-
-describe('NavbarComponent', () => {
-
-    const dataSource1: DataDiscoverySource = {
-        '@id': 'urn:source1',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'Example source1',
-        'schema:url': 'http://example1.com',
-        'schema:image': 'http://example1.com/logo.png'
-    };
-
-    const dataSource2: DataDiscoverySource = {
-        '@id': 'urn:source2',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'Example source2',
-        'schema:url': 'http://example2.com',
-        'schema:image': 'http://example2.com/logo.png'
-    };
-
-    let gnpisService;
-
-    beforeEach(() => {
-        gnpisService = jasmine.createSpyObj(
-            'GnpisService', [
-                'getSource',
-                'suggest'
-            ]
-        );
-        gnpisService.suggest.and.returnValue(of([dataSource1['@id'], dataSource2['@id']]));
-        gnpisService.getSource.withArgs(dataSource1['@id']).and.returnValue(of(dataSource1));
-        gnpisService.getSource.withArgs(dataSource2['@id']).and.returnValue(of(dataSource2));
-
-        TestBed.configureTestingModule({
-            declarations: [NavbarComponent],
-            providers: [
-                { provide: GnpisService, useValue: gnpisService }
-            ]
-        }).compileComponents();
-    });
-
-    it('should toggle the class on click', () => {
-        const tester = new NavbarComponentTester();
-
-        tester.detectChanges();
-        expect(tester.navBar.classes).toContain('collapse');
-
-        tester.toggler.click();
-        tester.detectChanges();
-        expect(tester.navBar.classes).not.toContain('collapse');
-    });
-
-    it('should display title and links that open in new tabs', async(() => {
-        const tester = new NavbarComponentTester();
-        const component = tester.componentInstance;
-
-        component.navbar = {
-            name: 'FAIDARE',
-            title: 'FAIR Data-finder for Agronomic REsearch',
-            logo: 'assets/applicationLogo.png',
-            links: [
-                { label: 'URGI', url: 'https://urgi.versailles.inra.fr/' }
-            ],
-            contributor: {
-                name: 'Elixir',
-                url: 'https://elixir-europe.org/',
-                logo: 'assets/elixir_logo.png'
-            }
-        };
-
-        tester.detectChanges();
-        expect(gnpisService.suggest).toHaveBeenCalledTimes(1);
-        expect(gnpisService.getSource).toHaveBeenCalledTimes(2);
-
-        expect(tester.logos.length).toBe(2);
-        expect(tester.logos.shift().attr('title')).toBe('FAIR Data-finder for Agronomic REsearch');
-        expect(tester.logos.pop().attr('title')).toBe('Elixir');
-
-        expect(tester.links.length).toBe(3);
-        // 'More...' section (containing Help, About, Join and Legal links) added automatically
-        // 'Data providers' section (containing data sources) fetch and added automatically
-
-        expect(tester.firstLink.textContent).toBe('URGI');
-        expect(tester.firstLink.attr('href')).toBe('https://urgi.versailles.inra.fr/');
-        expect(tester.firstLink.attr('target')).toBe('_blank');
-
-        expect(tester.providerLinks.length - 1).toBe(2);
-        // minus 1 because of the dropdown link
-        expect(tester.providerLinks.shift().textContent).toBe('Data providers');
-        expect(tester.providerLinks.pop().textContent).toBe('Example source2');
-        expect(tester.providerLinks.pop().attr('href')).toBe('http://example2.com');
-        expect(tester.providerLinks.pop().attr('target')).toBe('_blank');
-
-        expect(tester.links[2].element('a').textContent).toBe('More...');
-
-    }));
-
-})
-
-;
diff --git a/frontend/src/app/navbar/navbar.component.ts b/frontend/src/app/navbar/navbar.component.ts
deleted file mode 100644
index 6674354dea1c8237a2c29010ac0d6ef206dc199c..0000000000000000000000000000000000000000
--- a/frontend/src/app/navbar/navbar.component.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { environment } from '../../environments/environment';
-import { GnpisService } from '../gnpis.service';
-import { flatMap } from 'rxjs/operators';
-import { of } from 'rxjs/internal/observable/of';
-
-interface Link {
-    label: string;
-    url: string;
-    subMenu?: Link[];
-}
-interface Contributor {
-    name: string;
-    url: string;
-    logo: string;
-}
-
-interface NavBar {
-    name: string;
-    title: string;
-    logo: string;
-    links: Link[];
-    contributor: Contributor;
-}
-
-@Component({
-    selector: 'faidare-navbar',
-    templateUrl: './navbar.component.html',
-    styleUrls: ['./navbar.component.scss']
-})
-export class NavbarComponent implements OnInit {
-
-     /*displayBackButton = false;
-    previousQueryParam: Params;
-
-    constructor(private router: Router, private route: ActivatedRoute
-    ) {
-
-        this.router.events.subscribe(event => {
-            if (event instanceof RoutesRecognized) {
-                if (this.checkIsFormPage(event.url)) {
-                    this.displayBackButton = false;
-                    this.route.queryParams.subscribe(queryParam => {
-                        this.previousQueryParam = queryParam;
-                    });
-                } else {
-                    this.displayBackButton = true;
-                }
-            }
-        });
-    }*/
-
-    navbar: NavBar = environment.navbar;
-    navbarCollapsed = true;
-
-    dataProvider: Link = {
-        label: 'Data providers',
-        url: '#',
-        subMenu: []
-    };
-
-    constructor(private gnpisService: GnpisService) {
-    }
-
-    ngOnInit() {
-        // Fetch source URIs for with we have data
-        this.gnpisService.suggest('sources')
-            .pipe(
-                // Flatten observable of array of string into observable of string
-                flatMap(dataSourceURIs => of(...dataSourceURIs)),
-                // For each source URI get actual source description
-                flatMap(dataSourceURI => this.gnpisService.getSource(dataSourceURI)),
-            )
-            .subscribe(dataSource => {
-                // Add each data source to the nav bar, under 'Data providers'
-                this.dataProvider.subMenu.push({
-                    label: dataSource['schema:name'],
-                    url: dataSource['schema:url']
-                });
-            });
-        this.navbar.links.push(this.dataProvider);
-    }
-
-    toggleNavbar() {
-        this.navbarCollapsed = !this.navbarCollapsed;
-    }
-
-    /*checkIsFormPage(url: String) {
-        for (const route of appUrlRoutes) {
-            const routeType: string = route.path.split(':')[0];
-            if (routeType !== '' && url.startsWith('/' + routeType)) {
-                return false;
-            }
-        }
-        return true;
-    }*/
-}
diff --git a/frontend/src/app/result-page/document/document.component.html b/frontend/src/app/result-page/document/document.component.html
deleted file mode 100644
index 202773526873e97f04f4c0986a81d6a298e0da86..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/document/document.component.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<div class="mt-3 mb-3">
-  <h5>
-    <span *ngFor="let type of document['@type']"
-          class="badge {{ getBadgeType(type) }} mr-2">
-      {{ type }}
-    </span>
-    <a class="badge badge-source mr-2" [href]="dataSource['schema:url']" target="_blank">
-      {{ dataSource['schema:name'] }}
-    </a>
-    <a class="title" *ngIf="getRouterLink() && (document['@type'].includes('Phenotyping Study')  || document['@type'].includes('Genotyping Study'))"
-       [routerLink]="getRouterLink()">
-      {{ document["schema:name"] }}
-    </a>
-    <a class="title" *ngIf="getRouterLink() && !document['@type'].includes('Phenotyping Study') && !document['@type'].includes('Genotyping Study')"
-       [routerLink]="getRouterLink()" [queryParams]="getQueryParam()">
-      {{ document["schema:name"] }}
-    </a>
-  </h5>
-
-  <h5>
-    <a class="title" *ngIf="getURL()" [href]="getURL()" target="_blank">
-      ({{ dataSource['schema:name'] }} data source link)
-    </a>
-  </h5>
-  <span class="text-justify description">
-    <strong>Description: </strong>
-    <ng-container *ngIf="!needTruncation || opened">
-      {{ document["schema:description"] }}
-
-      <button *ngIf="needTruncation"
-              class="btn btn-link btn-inline"
-              (click)="toggleDescription()">
-        Reduce
-      </button>
-    </ng-container>
-
-    <ng-container *ngIf="needTruncation && !opened">
-      {{ getTruncatedDescription() }}
-
-      <button class="btn btn-link btn-inline"
-              (click)="toggleDescription()">
-        ...(Show More)
-      </button>
-    </ng-container>
-  </span>
-</div>
diff --git a/frontend/src/app/result-page/document/document.component.scss b/frontend/src/app/result-page/document/document.component.scss
deleted file mode 100644
index 03d7cf72dbfd8404e2dcc44f9d8f9267abdf84aa..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/document/document.component.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-
-.badge-source {
-  background-color: #b54646;
-  color: white;
-}
-
-.badge-germplasm {
-  background-color: #4aa434;
-  color: white;
-}
-
-.badge-phenotyping-study {
-  background-color: #437b9c;
-  color: white;
-}
-
-.badge-genotyping-study {
-  background-color: #c39d35;
-  color: white;
-}
diff --git a/frontend/src/app/result-page/document/document.component.spec.ts b/frontend/src/app/result-page/document/document.component.spec.ts
deleted file mode 100644
index f1261dfc57090e06e57b5a14f67a6330e34fe9bb..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/document/document.component.spec.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-
-import { DocumentComponent } from './document.component';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { DataDiscoverySource } from '../../models/data-discovery.model';
-import { ComponentTester, speculoosMatchers } from 'ngx-speculoos';
-
-describe('DocumentComponent', () => {
-    class DocumentComponentTester extends ComponentTester<DocumentComponent> {
-        constructor() {
-            super(DocumentComponent);
-        }
-
-        get types() {
-            return this.elements('h5 span');
-        }
-
-        get source() {
-            return this.element('h5 a.badge-source');
-        }
-
-        get title() {
-            return this.element('h5 a.title');
-        }
-
-        get description() {
-            return this.element('span.description');
-        }
-
-        get showMoreButton() {
-            return this.button('span.description button');
-        }
-    }
-
-    beforeEach(() => TestBed.configureTestingModule({
-        declarations: [DocumentComponent],
-        schemas: [NO_ERRORS_SCHEMA]
-    }));
-
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    it('should display document', () => {
-        const tester = new DocumentComponentTester();
-        const component = tester.componentInstance;
-
-        component.document = {
-            '@type': ['Germplasm', 'Phenotyping Study', 'Genotyping Study'],
-            '@id': 'urn',
-            'schema:identifier': 'doc1',
-            'schema:name': 'doc_name',
-            'schema:url': 'http://dco/url',
-            'schema:description': 'description',
-            'schema:includedInDataCatalog': {
-                '@id': 'http://source1.com',
-                '@type': ['schema:DataCatalog'],
-                'schema:image': null,
-                'schema:name': 'source1',
-                'schema:url': 'http://dco/url'
-            }
-        };
-        tester.detectChanges();
-        expect(component).toBeTruthy();
-        expect(tester.types[0]).toContainText('Germplasm');
-        expect(tester.types[0].classes).toContain('badge-germplasm');
-
-        expect(tester.types[1]).toContainText('Phenotyping Study');
-        expect(tester.types[1].classes).toContain('badge-phenotyping-study');
-
-        expect(tester.types[2]).toContainText('Genotyping Study');
-        expect(tester.types[2].classes).toContain('badge-genotyping-study');
-
-        expect(tester.source).toContainText('source1');
-        expect(tester.source.attr('href')).toEqual('http://dco/url');
-
-        expect(tester.title).toContainText('doc_name');
-        expect(tester.title.nativeElement['routerLink']).toEqual('/germplasm');
-
-        expect(tester.description).toContainText('description');
-
-    });
-
-
-    it('should generate router link', () => {
-        const tester = new DocumentComponentTester();
-        const component = tester.componentInstance;
-
-        component.document = {
-            '@type': ['Germplasm'],
-            '@id': 'urn',
-            'schema:identifier': 'g1',
-            'schema:name': 'doc_name',
-            'schema:url': null,
-            'schema:description': 'description',
-            'schema:includedInDataCatalog': {} as DataDiscoverySource
-        };
-        tester.detectChanges();
-        expect(component).toBeTruthy();
-
-        expect(tester.title).toContainText('doc_name');
-        expect(tester.title.nativeElement['routerLink']).toEqual('/germplasm');
-        expect(component.getQueryParam().id).toEqual('g1');
-
-    });
-
-    it('should truncate description', () => {
-        const tester = new DocumentComponentTester();
-        const component = tester.componentInstance;
-
-        component.document = {
-            '@type': ['Germplasm'],
-            '@id': 'urn',
-            'schema:identifier': 'g1',
-            'schema:name': 'doc_name',
-            'schema:url': null,
-            'schema:description': 'Lorem ipsum dolor sit amet, consectetur ' +
-                'adipiscing elit. Suspendisse velit purus, congue euismod ' +
-                'leo vel, pharetra euismod lorem. Suspendisse sed tempus ante, ' +
-                'eu mattis neque. Quisque eget dui feugiat, pulvinar mi vel, ' +
-                'imperdiet orci. Morbi ac mollis ex. Aliuam justo.',
-            'schema:includedInDataCatalog': {} as DataDiscoverySource
-        };
-        tester.detectChanges();
-        expect(component).toBeTruthy();
-
-        expect(tester.description).not.toContainText('justo');
-
-        expect(tester.showMoreButton).toBeTruthy();
-        tester.showMoreButton.click();
-
-        expect(tester.description).toContainText('justo');
-
-        expect(tester.showMoreButton).toBeTruthy();
-        tester.showMoreButton.click();
-
-        expect(tester.description).not.toContainText('justo');
-    });
-});
diff --git a/frontend/src/app/result-page/document/document.component.ts b/frontend/src/app/result-page/document/document.component.ts
deleted file mode 100644
index 72cae0f5d95b729f8a2c1fab3a1d20c931d4111a..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/document/document.component.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import {
-    DataDiscoveryDocument,
-    DataDiscoverySource,
-    DataDiscoveryType
-} from '../../models/data-discovery.model';
-
-@Component({
-    selector: 'faidare-document',
-    templateUrl: './document.component.html',
-    styleUrls: ['./document.component.scss']
-})
-export class DocumentComponent implements OnInit {
-    private static MAX_LENGTH = 256;
-    private static BADGE_TYPE = {
-        'Germplasm': 'badge-germplasm',
-        'Phenotyping Study': 'badge-phenotyping-study',
-        'Genotyping Study': 'badge-genotyping-study'
-    };
-
-    private static CARD_TYPE = {
-        'Germplasm': 'germplasm',
-        'Phenotyping Study': 'studies',
-        'Genotyping Study': 'studies'
-    };
-
-    @Input() document: DataDiscoveryDocument;
-    needTruncation = false;
-    opened = false;
-
-    get dataSource(): DataDiscoverySource {
-        return this.document['schema:includedInDataCatalog'];
-    }
-
-    getURL() {
-        return this.document['schema:url'] || '';
-    }
-
-    getRouterLink() {
-        for (const type of this.document['@type']) {
-            const cardUrl = DocumentComponent.CARD_TYPE[type];
-            if (cardUrl === 'studies') {
-                return `/${cardUrl}/${this.document['schema:identifier']}`;
-            }
-            if (cardUrl === 'germplasm') {
-                return `/${cardUrl}`;
-            }
-        }
-
-        return '';
-    }
-
-    getQueryParam() {
-        if (this.document['schema:identifier']) {
-            const id: string = this.document['schema:identifier'];
-            return { id: id };
-        } else {
-            return {
-                pui: this.document['@id']
-            };
-        }
-    }
-
-    getBadgeType(type: DataDiscoveryType) {
-        return DocumentComponent.BADGE_TYPE[type];
-    }
-
-    ngOnInit(): void {
-        this.needTruncation = this.document['schema:description'].length > DocumentComponent.MAX_LENGTH;
-    }
-
-    toggleDescription() {
-        this.opened = !this.opened;
-    }
-
-    getTruncatedDescription() {
-        return this.document['schema:description'].slice(0, DocumentComponent.MAX_LENGTH);
-    }
-}
diff --git a/frontend/src/app/result-page/result-page.component.html b/frontend/src/app/result-page/result-page.component.html
deleted file mode 100644
index 265a7e381762287c121d4b281eed9b6b52c34b84..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/result-page.component.html
+++ /dev/null
@@ -1,141 +0,0 @@
-<h3 align="center" class="mb-4">{{ appTitle }}</h3>
-
-
-<!-- Reset all button -->
-<div class="text-right">
-  <button type="button" class="btn btn-sm btn-danger mt-1"
-          (click)="resetAll()">
-    Reset all
-  </button>
-</div>
-
-<div class="row">
-
-  <!-- Column for facets -->
-  <div class="col-3">
-    <faidare-facets
-      [criteria$]="criteria$"
-      [facets]="facets"
-      [displayGermplasmResult$]="displayGermplasmResult$"
-      [germplasmSearchCriteria$]="germplasmSearchCriteria$">
-    </faidare-facets>
-
-    <faidare-facets
-      *ngIf="displayGermplasmResult && germplasmfacets.length"
-      [facets]="germplasmfacets"
-      [criteria$]="criteria$"
-      [displayGermplasmResult$]="displayGermplasmResult$"
-      [germplasmSearchCriteria$]="germplasmSearchCriteria$">
-    </faidare-facets>
-  </div>
-
-
-  <!-- Column for form and results -->
-  <div class="col-9">
-    <div class="row">
-
-      <div class="col-12">
-        <!-- Form -->
-        <faidare-form
-          #form
-          [criteria$]="criteria$"
-          [displayGermplasmResult$]="displayGermplasmResult$">
-        </faidare-form>
-      </div>
-
-      <div class="col-12">
-        <!-- Loading spinner-->
-        <div class="text-center">
-          <faidare-loading-spinner
-            [loading]="loading"></faidare-loading-spinner>
-        </div>
-
-        <!-- No criteria selected -->
-        <div *ngIf="criteriaIsEmpty && !loading"
-             class="text-center text-muted mt-5 bolder">
-          Select criteria to get results.
-        </div>
-
-
-        <!-- Display results when possible -->
-        <ng-container
-          *ngIf="documents.length && !criteriaIsEmpty && !loading && !displayGermplasmResult">
-          <!-- Pagination status -->
-          <div class="container">
-            <div class="row result align-content-center">
-          <span class="col-4 mt-2 bolder">
-            Results:
-          </span>
-              <span *ngIf="pagination.totalResult"
-                    class="col-8 text-right small text-muted mt-3">
-          From {{ pagination.startResult | number }}
-                to {{ pagination.endResult | number }}
-                over {{ pagination.totalResult | number }} documents
-          <span *ngIf="pagination.totalResult > pagination.maxResults">
-          (limited to {{ pagination.maxResults | number }})
-          </span>
-        </span>
-            </div>
-          </div>
-
-          <!--Top page navigator-->
-          <div class="d-flex justify-content-center mt-3"
-               *ngIf="pagination.totalPages > 1">
-            <!-- we add 1 to the page because ngb-pagination is 1 based -->
-            <ngb-pagination [page]="pagination.currentPage + 1"
-                            (pageChange)="changePage($event)"
-                            [collectionSize]="resultCount()"
-                            [pageSize]="pagination.pageSize"
-                            [maxSize]="5"
-                            [boundaryLinks]="true"
-                            [ellipses]="false"
-                            size="sm">
-            </ngb-pagination>
-          </div>
-
-          <!-- Result document -->
-          <faidare-document
-            *ngFor="let document of documents"
-            [document]="document">
-          </faidare-document>
-
-          <!-- Pagination -->
-          <!--Bottom page navigator-->
-          <div class="d-flex justify-content-center mt-4 mb-5"
-               *ngIf="pagination.totalPages > 1">
-            <!-- we add 1 to the page because ngb-pagination is 1 based -->
-            <ngb-pagination [page]="pagination.currentPage + 1"
-                            (pageChange)="changePage($event)"
-                            [collectionSize]="resultCount()"
-                            [pageSize]="pagination.pageSize"
-                            [maxSize]="5"
-                            [boundaryLinks]="true"
-                            [ellipses]="false"
-                            size="sm">
-            </ngb-pagination>
-          </div>
-        </ng-container>
-
-        <!-- Display the table of the germplasm-result-page -->
-        <ng-container *ngIf="displayGermplasmResult">
-          <faidare-germplasm-result-page
-            [criteriaFromForm$]=criteria$
-            [germplasmSearchCriteria$]="germplasmSearchCriteria$"
-            [germplasmFacets$]="germplasmfacets$">
-          </faidare-germplasm-result-page>
-        </ng-container>
-
-        <!-- Else we display a simple message when no result found -->
-        <div *ngIf="pagination.totalResult == 0 && !loading
-    && (!criteriaIsEmpty && !displayGermplasmResult)"
-             id="no-results" class="text-center">
-          <div class="no-result-icon">
-            <span class="fa fa-meh-o"></span>
-          </div>
-          No results.
-        </div>
-
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/frontend/src/app/result-page/result-page.component.scss b/frontend/src/app/result-page/result-page.component.scss
deleted file mode 100644
index 7e5e103787017f47102f6aa78d82359266ee9f52..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/result-page.component.scss
+++ /dev/null
@@ -1,100 +0,0 @@
-@import "theme";
-
-.no-result-icon {
-  font-size: 8rem;
-  color: $gray-300;
-}
-
-.result {
-  border-top: 4.5px solid #c2c2c2;
-  border-bottom: 1px solid #c2c2c2;
-}
-
-.bolder {
-  font-size: 1.2rem;
-  font-weight: bold;
-}
-
-// Loading spinner
-.lds-spinner {
-  $scale: 0.75;
-
-  color: black;
-  display: block;
-  position: relative;
-  width: 64px * $scale;
-  height: 64px * $scale;
-
-  div {
-    transform-origin: 32px * $scale 32px * $scale;
-    animation: lds-spinner 1.2s linear infinite;
-  }
-  div:after {
-    content: " ";
-    display: block;
-    position: absolute;
-    top: 3px;
-    left: 29px * $scale;
-    width: 5px * $scale;
-    height: 14px * $scale;
-    border-radius: 20%;
-    background: black;
-  }
-  div:nth-child(1) {
-    transform: rotate(0deg);
-    animation-delay: -1.1s;
-  }
-  div:nth-child(2) {
-    transform: rotate(30deg);
-    animation-delay: -1s;
-  }
-  div:nth-child(3) {
-    transform: rotate(60deg);
-    animation-delay: -0.9s;
-  }
-  div:nth-child(4) {
-    transform: rotate(90deg);
-    animation-delay: -0.8s;
-  }
-  div:nth-child(5) {
-    transform: rotate(120deg);
-    animation-delay: -0.7s;
-  }
-  div:nth-child(6) {
-    transform: rotate(150deg);
-    animation-delay: -0.6s;
-  }
-  div:nth-child(7) {
-    transform: rotate(180deg);
-    animation-delay: -0.5s;
-  }
-  div:nth-child(8) {
-    transform: rotate(210deg);
-    animation-delay: -0.4s;
-  }
-  div:nth-child(9) {
-    transform: rotate(240deg);
-    animation-delay: -0.3s;
-  }
-  div:nth-child(10) {
-    transform: rotate(270deg);
-    animation-delay: -0.2s;
-  }
-  div:nth-child(11) {
-    transform: rotate(300deg);
-    animation-delay: -0.1s;
-  }
-  div:nth-child(12) {
-    transform: rotate(330deg);
-    animation-delay: 0s;
-  }
-}
-
-@keyframes lds-spinner {
-  0% {
-    opacity: 1;
-  }
-  100% {
-    opacity: 0;
-  }
-}
diff --git a/frontend/src/app/result-page/result-page.component.spec.ts b/frontend/src/app/result-page/result-page.component.spec.ts
deleted file mode 100644
index 145bb866c1bc67992ce1fee493b1e3a948cacd1a..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/result-page.component.spec.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-
-import { ResultPageComponent } from './result-page.component';
-import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
-import { RouterTestingModule } from '@angular/router/testing';
-import { ActivatedRoute, ActivatedRouteSnapshot, Params, Router } from '@angular/router';
-import { BehaviorSubject, of } from 'rxjs';
-import { ComponentTester, fakeRoute } from 'ngx-speculoos';
-import { DocumentComponent } from './document/document.component';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryDocument,
-    DataDiscoverySource
-} from '../models/data-discovery.model';
-import { GnpisService } from '../gnpis.service';
-import { BrapiResults } from '../models/brapi.model';
-
-
-class ResultPageComponentTester extends ComponentTester<ResultPageComponent> {
-    constructor() {
-        super(ResultPageComponent);
-        this.componentInstance.form.traitWidgetInitialized = new EventEmitter();
-        this.componentInstance.form.traitWidgetInitialized.emit();
-    }
-}
-
-describe('ResultPageComponent', () => {
-
-    const service = jasmine.createSpyObj(
-        'GnpisService', ['search']
-    );
-    const params = {
-        crops: 'Genus',
-        germplasmLists: ['Panel 1', 'Collection 2']
-    } as Params;
-    const activatedRoute = fakeRoute({
-        queryParams: of(params),
-        snapshot: {
-            queryParams: params
-        } as ActivatedRouteSnapshot
-    });
-
-    const document: DataDiscoveryDocument = {
-        '@type': ['Germplasm'],
-        '@id': 'urn',
-        'schema:identifier': 'schema',
-        'schema:name': 'doc_name',
-        'schema:url': 'http://dco/url',
-        'schema:description': 'description',
-        'schema:includedInDataCatalog': {} as DataDiscoverySource
-    };
-    const searchedDocuments: BrapiResults<DataDiscoveryDocument> = {
-        result: {
-            data: [document]
-        },
-        metadata: {
-            pagination: {
-                pageSize: 10,
-                currentPage: 0,
-                totalPages: 1,
-                totalCount: 1
-            }
-        }
-    };
-    service.search.and.returnValue(of(searchedDocuments));
-
-    beforeEach(() => TestBed.configureTestingModule({
-        imports: [
-            RouterTestingModule,
-        ],
-        declarations: [ResultPageComponent, DocumentComponent],
-        providers: [
-            { provide: GnpisService, useValue: service },
-            { provide: ActivatedRoute, useValue: activatedRoute }
-        ],
-        schemas: [NO_ERRORS_SCHEMA],
-    }));
-
-
-    it('should generate criteria from URL', () => {
-        const tester = new ResultPageComponentTester();
-        const component = tester.componentInstance;
-        component.criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-
-        tester.detectChanges();
-        component.criteria$.subscribe(criteria => {
-            expect(criteria.crops).toEqual([params.crops]);
-            expect(criteria.germplasmLists).toEqual(params.germplasmLists);
-        });
-    });
-
-
-    it('should navigate on criteria change', () => {
-        const tester = new ResultPageComponentTester();
-        const component = tester.componentInstance;
-
-        const router = TestBed.get(Router) as Router;
-        spyOn(router, 'navigate');
-        tester.detectChanges();
-
-        const criteria = { crops: ['Wheat', 'Vitis'] } as DataDiscoveryCriteria;
-        component.criteria$.next(criteria);
-        const newQueryParams = {
-            crops: criteria.crops,
-            accessions: criteria.accessions,
-            germplasmLists: criteria.germplasmLists,
-            observationVariableIds: criteria.topSelectedTraitOntologyIds,
-            sources: criteria.sources,
-            types: criteria.types,
-            page: 1
-        };
-
-        expect(router.navigate).toHaveBeenCalledWith(['.'], {
-            relativeTo: activatedRoute,
-            queryParams: newQueryParams
-        });
-
-    });
-
-    it('should fetch documents', () => {
-        const tester = new ResultPageComponentTester();
-        const component = tester.componentInstance;
-        component.fetchDocumentsAndFacets();
-        expect(component.documents).not.toBe(null);
-    });
-});
diff --git a/frontend/src/app/result-page/result-page.component.ts b/frontend/src/app/result-page/result-page.component.ts
deleted file mode 100644
index 1005b86317455cb1d8d825bbd4bffb194da12416..0000000000000000000000000000000000000000
--- a/frontend/src/app/result-page/result-page.component.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
-import { ActivatedRoute, NavigationStart, Router } from '@angular/router';
-import {
-    DataDiscoveryCriteria,
-    DataDiscoveryCriteriaUtils,
-    DataDiscoveryDocument,
-    DataDiscoveryFacet,
-    DEFAULT_PAGE_SIZE,
-    MAX_RESULTS
-} from '../models/data-discovery.model';
-import { BehaviorSubject } from 'rxjs';
-import { GnpisService } from '../gnpis.service';
-import { filter } from 'rxjs/operators';
-import { FormComponent } from '../form/form.component';
-import { environment } from '../../environments/environment';
-import { GermplasmSearchCriteria } from '../models/gnpis.model';
-
-
-@Component({
-    selector: 'faidare-result',
-    templateUrl: './result-page.component.html',
-    styleUrls: ['./result-page.component.scss'],
-})
-export class ResultPageComponent implements OnInit {
-
-    @ViewChild('form') form: FormComponent;
-    appTitle: string = environment.appTitle;
-
-    criteria$ = new BehaviorSubject<DataDiscoveryCriteria>(DataDiscoveryCriteriaUtils.emptyCriteria());
-    documents: DataDiscoveryDocument[] = [];
-    facets: DataDiscoveryFacet[] = [];
-    germplasmSearchCriteria$ = new BehaviorSubject<GermplasmSearchCriteria>(DataDiscoveryCriteriaUtils.emptyGermplasmSearchCriteria());
-    germplasmfacets$ = new BehaviorSubject<DataDiscoveryFacet[]>([]);
-    germplasmfacets: DataDiscoveryFacet[] = [];
-    pagination = {
-        startResult: 1,
-        endResult: DEFAULT_PAGE_SIZE,
-        totalResult: null,
-        currentPage: 0,
-        pageSize: DEFAULT_PAGE_SIZE,
-        totalPages: null,
-        maxResults: MAX_RESULTS
-    };
-
-    criteriaIsEmpty = true;
-    displayGermplasmResult$ = new BehaviorSubject(false);
-    displayGermplasmResult = false;
-    loading = true;
-
-    constructor(private route: ActivatedRoute,
-                private router: Router,
-                private gnpisService: GnpisService,
-    ) {
-    }
-
-    fetchDocumentsAndFacets() {
-        this.loading = true;
-        const criteria = this.criteria$.value;
-        this.gnpisService.search(criteria)
-            .subscribe(({ metadata, result, facets }) => {
-                this.loading = false;
-                this.documents = result.data;
-                DataDiscoveryCriteriaUtils.updatePagination(this.pagination, metadata.pagination);
-                this.facets = facets;
-            });
-    }
-
-    ngOnInit(): void {
-        const queryParams = this.route.snapshot.queryParams;
-        this.router.events.subscribe((event) => {
-            if (event instanceof NavigationStart) {
-                this.displayGermplasmResult = false;
-            }
-        });
-
-        // Parse criteria from URL query params
-        const initialCriteria = DataDiscoveryCriteriaUtils.fromQueryParams(queryParams);
-        this.criteria$.next(initialCriteria);
-
-        this.criteriaIsEmpty = DataDiscoveryCriteriaUtils.checkCriteriaIsEmpty(initialCriteria);
-
-
-        this.form.traitWidgetInitialized.subscribe(() => {
-            this.fetchDocumentsAndFacets();
-        });
-
-        this.displayGermplasmResult$.subscribe(value => {
-            this.displayGermplasmResult = value;
-        });
-        this.displayGermplasmResult$.next(this.displayGermplasmResult);
-
-        this.criteria$
-            .pipe(filter(c => c !== initialCriteria))
-            .subscribe(newCriteria => {
-                // Reset pagination
-                newCriteria.page = 0;
-                // Fetch documents and facets
-                this.fetchDocumentsAndFacets();
-                this.criteriaIsEmpty = DataDiscoveryCriteriaUtils.checkCriteriaIsEmpty(newCriteria);
-
-                if (!this.displayGermplasmResult) {
-                    // Update URL query params
-                    this.router.navigate(['.'], {
-                        relativeTo: this.route,
-                        queryParams: DataDiscoveryCriteriaUtils.toQueryParams(newCriteria)
-                    });
-                }
-            });
-
-        this.germplasmfacets$.subscribe(facets => {
-            this.germplasmfacets = facets;
-        });
-    }
-
-    resultCount() {
-        return Math.min(
-            this.pagination.totalResult,
-            MAX_RESULTS - DEFAULT_PAGE_SIZE
-        );
-    }
-
-    resetAll() {
-        this.router.navigate(['.'], {
-            relativeTo: this.route,
-
-            // Use of empty param to force re-parse of URL in ngOnInit
-            queryParams: { empty: [] }
-        });
-        this.displayGermplasmResult$.next(false);
-        this.criteria$.next(DataDiscoveryCriteriaUtils.emptyCriteria());
-    }
-
-    changePage(page: number) {
-        const criteria = this.criteria$.value;
-        criteria.page = page - 1;
-        this.fetchDocumentsAndFacets();
-        this.router.navigate(['.'], {
-            relativeTo: this.route,
-            queryParams: { page },
-            queryParamsHandling: 'merge'
-        });
-    }
-
-}
diff --git a/frontend/src/app/site-card/site-card.component.html b/frontend/src/app/site-card/site-card.component.html
deleted file mode 100644
index 0a8f72355067335c4139ef656b61aef8283672c0..0000000000000000000000000000000000000000
--- a/frontend/src/app/site-card/site-card.component.html
+++ /dev/null
@@ -1,186 +0,0 @@
-<faidare-loading-spinner [loading]="loading" class="float-right"></faidare-loading-spinner>
-
-<ng-container *ngIf="location">
-  <h3 class="mb-4">
-    Site: {{ location.locationName }}
-
-
-  </h3>
-
-  <faidare-map [locations]="[location]"></faidare-map>
-
-
-
-  <faidare-card-section
-    header="Details">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-         <!-- Display generic document details (PUI, data source links, etc.) -->
-        <faidare-card-generic-document
-          [document]="location"
-          documentType="location">
-        </faidare-card-generic-document>
-
-        <faidare-card-row
-          label="Abbreviation"
-          [value]="location.abbreviation">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Type"
-          [value]="location.locationType">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Status"
-          [test]="location.additionalInfo && location.additionalInfo['Site status']">
-          <ng-template>
-            {{ location.additionalInfo['Site status'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Institution/Landowner"
-          [value]="location.instituteName">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Institution address"
-          [value]="location.instituteAddress">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Coordinates precision"
-          [test]="location.additionalInfo && location.additionalInfo['Coordinates precision']">
-          <ng-template>
-            {{ location.additionalInfo['Coordinates precision'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Latitude"
-          [test]="location.latitude">
-          <ng-template>
-            {{ location.latitude }} ({{ location.latitude | coordinates:type.ToDegrees:direction.Latitude }})
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Longitude"
-          [test]="location.longitude">
-          <ng-template>
-            {{ location.longitude }} ({{ location.longitude | coordinates:type.ToDegrees:direction.Longitude }})
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Geographical location"
-          [test]="location.additionalInfo && location.additionalInfo['Geographical location']">
-          <ng-template>
-            {{ location.additionalInfo['Geographical location'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Country name"
-          [test]="location.countryName">
-          <ng-template>
-            {{ location.countryName }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Country code"
-          [test]="location.countryCode">
-          <ng-template>
-            {{ location.countryCode }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Altitude"
-          [value]="location.altitude">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Slope"
-          [test]="location.additionalInfo && location.additionalInfo['Slope']">
-          <ng-template>
-            {{ location.additionalInfo['Slope'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Exposure"
-          [test]="location.additionalInfo && location.additionalInfo['Exposure']">
-          <ng-template>
-            {{ location.additionalInfo['Exposure'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Topography"
-          [test]="location.additionalInfo && location.additionalInfo['Topography']">
-          <ng-template>
-            {{ location.additionalInfo['Topography'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Environment type"
-          [test]="location.additionalInfo && location.additionalInfo['Environment type']">
-          <ng-template>
-            {{ location.additionalInfo['Environment type'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Distance to city"
-          [test]="location.additionalInfo && location.additionalInfo['Distance to city']">
-          <ng-template>
-            {{ location.additionalInfo['Distance to city'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Direction from city"
-          [test]="location.additionalInfo && location.additionalInfo['Direction from city']">
-          <ng-template>
-            {{ location.additionalInfo['Direction from city'] }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Comment"
-          [test]="location.additionalInfo && location.additionalInfo['Comment']">
-          <ng-template>
-            {{ location.additionalInfo['Comment'] }}
-          </ng-template>
-        </faidare-card-row>
-
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <faidare-card-section
-    header="Additional information"
-    [test]="additionalInfos && additionalInfos.length > 0">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-        <ng-container *ngFor="let additionalInfo of additionalInfos">
-          <faidare-card-row
-            [label]="additionalInfo.key"
-            [value]="additionalInfo.value">
-          </faidare-card-row>
-        </ng-container>
-
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--XRefs part -->
-  <faidare-xrefs [xrefId]="location.locationDbId"></faidare-xrefs>
-
-</ng-container>
diff --git a/frontend/src/app/site-card/site-card.component.scss b/frontend/src/app/site-card/site-card.component.scss
deleted file mode 100644
index bb109da81d37b2df40a8dfdbeaaeaf748312932e..0000000000000000000000000000000000000000
--- a/frontend/src/app/site-card/site-card.component.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-@import "theme";
-@import '../../styles.scss';
-
-a:not([href]):not([tabindex]) {
-  color: #0f6fa1;
-  cursor: pointer;
-}
-
-a:not([href]):not([tabindex]):hover {
-  text-decoration: underline;
-}
-
diff --git a/frontend/src/app/site-card/site-card.component.spec.ts b/frontend/src/app/site-card/site-card.component.spec.ts
deleted file mode 100644
index a739104e9b0c99bab99b8dfaeb4fb7d3a80f8f91..0000000000000000000000000000000000000000
--- a/frontend/src/app/site-card/site-card.component.spec.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { SiteCardComponent } from './site-card.component';
-import { MapComponent } from '../map/map.component';
-import { BrapiService } from '../brapi.service';
-import { ActivatedRoute, convertToParamMap } from '@angular/router';
-import { of } from 'rxjs';
-import { BrapiLocation, BrapiResult } from '../models/brapi.model';
-import { CardRowComponent } from '../card-row/card-row.component';
-import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component';
-import { CardTableComponent } from '../card-table/card-table.component';
-import { CardSectionComponent } from '../card-section/card-section.component';
-import { DataDiscoverySource } from '../models/data-discovery.model';
-import { GnpisService } from '../gnpis.service';
-import { MockComponent } from 'ng-mocks';
-import { XrefsComponent } from '../xrefs/xrefs.component';
-import { CoordinatesPipe, CoordinatesService } from 'angular-coordinates';
-import { CardGenericDocumentComponent } from '../card-generic-document/card-generic-document.component';
-
-
-describe('SiteCardComponent', () => {
-    const brapiService = jasmine.createSpyObj(
-        'BrapiService', ['location']
-    );
-    const gnpisService = jasmine.createSpyObj(
-        'GnpisService', ['getSource']
-    );
-    const coordinatesService = jasmine.createSpyObj(
-        'CoordinatesService', ['transform']
-    );
-
-    const response: BrapiResult<BrapiLocation> = {
-        metadata: null,
-        result: {
-            locationDbId: '1',
-            latitude: 1,
-            longitude: 1,
-            altitude: 1,
-            instituteName: '',
-            instituteAddress: '',
-            countryName: '',
-            countryCode: '',
-            locationType: '',
-            abbreviation: '',
-            locationName: 'site1',
-            additionalInfo: {
-                Topography: '',
-                Slope: '',
-                Comment: '',
-                Exposure: '',
-                'Coordinates precision': '',
-                'Direction from city': '',
-                'Distance to city': '',
-                'Environment type': '',
-                'Geographical location': '',
-                'Site status': ''
-            }
-        }
-    };
-
-    const source: DataDiscoverySource = {
-        '@id': 'src1',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'source1',
-        'schema:url': 'srcUrl',
-        'schema:image': null
-    };
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            declarations: [
-                SiteCardComponent, MapComponent, LoadingSpinnerComponent,
-                CardRowComponent, CardSectionComponent, CardTableComponent, CoordinatesPipe,
-                MockComponent(CardGenericDocumentComponent), MockComponent(XrefsComponent)
-            ],
-            providers: [
-                { provide: BrapiService, useValue: brapiService },
-                { provide: GnpisService, useValue: gnpisService },
-                { provide: CoordinatesService, useValue: coordinatesService },
-                {
-                    provide: ActivatedRoute,
-                    useValue: {
-                        paramMap: of(convertToParamMap({ id: 1 }))
-                    }
-                }
-            ]
-        });
-    }));
-
-    it('should create component', () => {
-        const fixture = TestBed.createComponent(SiteCardComponent);
-        const component = fixture.componentInstance;
-        expect(component).toBeTruthy();
-    });
-
-    it('should display site', () => {
-        const fixture = TestBed.createComponent(SiteCardComponent);
-        brapiService.location.and.returnValues(of(response));
-        gnpisService.getSource.and.returnValue(of(source));
-        fixture.detectChanges();
-        const element = fixture.nativeElement;
-        expect(element.querySelector('h3').textContent).toBe(' Site: site1 ');
-    });
-});
diff --git a/frontend/src/app/site-card/site-card.component.ts b/frontend/src/app/site-card/site-card.component.ts
deleted file mode 100644
index 2d8227bb10e3233c61aaaad5b4ba783c614e82fb..0000000000000000000000000000000000000000
--- a/frontend/src/app/site-card/site-card.component.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { BrapiService } from '../brapi.service';
-import { ActivatedRoute } from '@angular/router';
-import { BrapiLocation } from '../models/brapi.model';
-import { KeyValueObject, toKeyValueObjects } from '../utils';
-import { DataDiscoverySource } from '../models/data-discovery.model';
-import { GnpisService } from '../gnpis.service';
-import { Direction, TransformationType } from 'angular-coordinates';
-
-@Component({
-    selector: 'faidare-site-card',
-    templateUrl: './site-card.component.html',
-    styleUrls: ['./site-card.component.scss']
-})
-export class SiteCardComponent implements OnInit {
-
-    location: BrapiLocation;
-    locationSource: DataDiscoverySource;
-    additionalInfos: KeyValueObject[];
-    direction = Direction;
-    type = TransformationType;
-    loading = true;
-
-    constructor(private brapiService: BrapiService, private gnpisService: GnpisService, private route: ActivatedRoute) {
-    }
-
-    ngOnInit() {
-        this.route.paramMap.subscribe(paramMap => {
-            // initialize site from location ID
-            const locationId = paramMap.get('id');
-            this.brapiService.location(locationId).subscribe(
-                response => {
-                    this.location = response.result;
-                    this.additionalInfos = [];
-                    if (this.location.additionalInfo) {
-                        this.manageAdditionalInfo(toKeyValueObjects(this.location.additionalInfo).sort());
-                    }
-                    this.locationSource = location['schema:includedInDataCatalog'];
-                    this.loading = false;
-                }
-            );
-        });
-
-    }
-
-    manageAdditionalInfo(keyValues: KeyValueObject[]) {
-        const forbiddenElements: String[] = [
-            'Site status',
-            'Coordinates precision',
-            'Slope',
-            'Exposure',
-            'Geographical location',
-            'Distance to city',
-            'Direction from city',
-            'Environment type',
-            'Topography',
-            'Comment'];
-        for (const keyValue of keyValues) {
-            if (!forbiddenElements.includes(keyValue.key)) {
-                this.additionalInfos.push(keyValue);
-            }
-        }
-    }
-}
-
diff --git a/frontend/src/app/study-card/study-card.component.html b/frontend/src/app/study-card/study-card.component.html
deleted file mode 100644
index b650a37afceb0732ee8a14d115eb94a8105bae5b..0000000000000000000000000000000000000000
--- a/frontend/src/app/study-card/study-card.component.html
+++ /dev/null
@@ -1,242 +0,0 @@
-<faidare-loading-spinner [loading]="loading" class="float-right"></faidare-loading-spinner>
-
-<ng-container *ngIf="study && !loading">
-  <h3 class="mb-4">
-    Study {{ study.studyType }}: {{ study.studyName }}
-  </h3>
-
-  <!-- Display the map -->
-  <faidare-map [locations]="[location]"></faidare-map>
-
-  <!-- Display the study's info -->
-  <faidare-card-section
-    header="Identification">
-    <ng-template>
-      <div class="card-body card-section-body">
-
-        <faidare-card-row
-          label="Name"
-          [value]="study.studyName">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Identifier"
-          [value]="study.studyDbId">
-        </faidare-card-row>
-
-         <!-- Display generic document details (PUI, data source links, etc.) -->
-        <faidare-card-generic-document
-          [document]="study"
-          documentType="study">
-        </faidare-card-generic-document>
-
-        <faidare-card-row
-          label="Project name"
-          [value]="study.programName">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Description"
-          [value]="study.studyDescription">
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Active"
-          [test]="study.active != null">
-          <ng-template>
-            {{ study.active ? "Yes" : "No" }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Seasons"
-          [test]="study.seasons && study.seasons.length != 0">
-          <ng-template>
-            {{ study.seasons.join(', ') }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Date"
-          [test]="study.startDate">
-          <ng-template>
-            {{ study.endDate ?
-            'From ' + study.startDate + ' to ' + study.endDate :
-            'Started on ' + study.startDate }}
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Location name"
-          [test]="study.locationDbId">
-          <ng-template>
-            <a [routerLink]="['/sites', study.locationDbId]">
-              {{ study.locationName }}
-            </a>
-          </ng-template>
-        </faidare-card-row>
-
-        <faidare-card-row
-          label="Data files"
-          [test]="study.dataLinks && study.dataLinks.length != 0">
-          <ng-template>
-            <div *ngFor="let dataLink of study.dataLinks">
-              <a target="_blank" [href]="dataLink.url">
-                {{ dataLink.name }}
-              </a>
-            </div>
-          </ng-template>
-        </faidare-card-row>
-      </div>
-
-    </ng-template>
-  </faidare-card-section>
-
-
-  <faidare-card-section
-    header="Genotype"
-    [test]="studyGermplasms && studyGermplasms.length != 0">
-    <ng-template>
-      <div class="table-responsive scroll-table table-card-body">
-        <faidare-card-table
-          [headers]="[
-          'Accession number',
-          'Name',
-          'Taxon'
-        ]"
-        [rows]="studyGermplasms">
-        <ng-template let-row>
-          <tr>
-            <td>
-              <a [routerLink]="'/germplasm'" [queryParams]="{id:row.germplasmDbId}">
-                {{ row.accessionNumber }}
-              </a>
-            </td>
-            <td>{{ row.germplasmName }}</td>
-            <td>{{ row.genus }} {{ row.species }} {{ row.subtaxa }}</td>
-          </tr>
-        </ng-template>
-      </faidare-card-table>
-     </div>
-    </ng-template>
-  </faidare-card-section>
-
-
-  <faidare-card-section
-    header="Variables"
-    [test]="studyObservationVariables && studyObservationVariables.length != 0">
-    <ng-template>
-      <div class="table-responsive scroll-table table-card-body">
-        <faidare-card-table
-          [headers]="[
-          'Variable id',
-          'Variable short name',
-          'Variable long name',
-          'Ontology name',
-          'Trait description'
-        ]"
-        [rows]="studyObservationVariables">
-        <ng-template let-row>
-          <tr>
-            <td>
-              <ng-template #name>{{ row.observationVariableDbId }}</ng-template>
-              <ng-template #link>
-                <a target="_blank" [href]=row.documentationURL>{{ row.observationVariableDbId }}</a>
-              </ng-template>
-              <ng-container *ngIf="row.documentationURL; then link else name"></ng-container>
-            </td>
-            <td>{{ row.name }}</td>
-            <td>{{ row.synonyms[0] }}</td>
-            <td>{{ row.ontologyName }}</td>
-            <td>{{ row.trait.description }}</td>
-          </tr>
-        </ng-template>
-       </faidare-card-table>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <faidare-card-section
-    header="Data Set"
-    [test]="studyDataset && studyDataset.length != 0">
-    <ng-template>
-      <div class="table-responsive scroll-big-table table-card-body">
-        <faidare-card-table
-          [headers]="[
-          'Name',
-          'Type',
-          'Linked studies identifiers'
-        ]"
-        [rows]="studyDataset">
-        <ng-template let-row>
-          <tr>
-            <td>
-              <ng-template #name>{{ row.trialName }}</ng-template>
-              <ng-template #link>
-                <a target="_blank" [href]=row.documentationURL>{{ row.trialName }}</a>
-              </ng-template>
-              <ng-container *ngIf="row.documentationURL; then link else name"></ng-container>
-            </td>
-            <td>{{ row.trialType }}</td>
-            <td width="60%">
-              <ng-container *ngFor="let trialStudy of row.studies">
-                <a
-                  [routerLink]="['/studies', trialStudy.studyDbId]">
-                  {{ trialStudy.studyName.trim() }}
-                </a>;
-              </ng-container>
-            </td>
-          </tr>
-        </ng-template>
-       </faidare-card-table>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <faidare-card-section
-    header="Contact"
-    [test]="study.contacts && study.contacts.length != 0">
-    <ng-template>
-      <div class="table-responsive scroll-table table-card-body">
-        <faidare-card-table
-          [headers]="[
-          'Role',
-          'Name',
-          'Email',
-          'Institution'
-        ]"
-          [rows]="study.contacts">
-        <ng-template let-row>
-          <tr>
-            <td>{{ row.type }}</td>
-            <td>{{ row.name }}</td>
-            <td>{{ row.email }}</td>
-            <td>{{ row.institutionName }}</td>
-          </tr>
-        </ng-template>
-       </faidare-card-table>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <faidare-card-section
-    header="Additional information"
-    [test]="additionalInfos && additionalInfos.length != 0">
-    <ng-template>
-      <div class="table-responsive scroll-table table-card-body">
-        <faidare-card-table
-         [rows]="additionalInfos">
-         <ng-template let-row>
-          <tr>
-            <td width="50%">{{ row.key }}</td>
-            <td>{{ row.value }}</td>
-          </tr>
-         </ng-template>
-        </faidare-card-table>
-      </div>
-    </ng-template>
-  </faidare-card-section>
-
-  <!--XRefs part -->
-  <faidare-xrefs [xrefId]="study.studyDbId"></faidare-xrefs>
-</ng-container>
diff --git a/frontend/src/app/study-card/study-card.component.scss b/frontend/src/app/study-card/study-card.component.scss
deleted file mode 100644
index f0376501baaeced5c8d3194b0d2d23faff4269fe..0000000000000000000000000000000000000000
--- a/frontend/src/app/study-card/study-card.component.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-@import "theme";
-@import '../../styles.scss';
-
-a:not([href]):not([tabindex]) {
-  color: #0f6fa1;
-  cursor: pointer;
-}
-
-a:not([href]):not([tabindex]):hover {
-  text-decoration: underline;
-}
diff --git a/frontend/src/app/study-card/study-card.component.spec.ts b/frontend/src/app/study-card/study-card.component.spec.ts
deleted file mode 100644
index 22eb6e081a8cca5d25cdffca53a53f58decda0fa..0000000000000000000000000000000000000000
--- a/frontend/src/app/study-card/study-card.component.spec.ts
+++ /dev/null
@@ -1,321 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { StudyCardComponent } from './study-card.component';
-import { ComponentTester, fakeRoute, speculoosMatchers } from 'ngx-speculoos';
-import { ActivatedRoute } from '@angular/router';
-import { of } from 'rxjs';
-import {
-    BrapiContacts,
-    BrapiGermplasm,
-    BrapiLocation,
-    BrapiObservationVariable,
-    BrapiResult,
-    BrapiResults,
-    BrapiStudy,
-    BrapiTrial
-} from '../models/brapi.model';
-import { BrapiService } from '../brapi.service';
-import { DataDiscoverySource } from '../models/data-discovery.model';
-import { MapComponent } from '../map/map.component';
-import { RouterTestingModule } from '@angular/router/testing';
-import { CardSectionComponent } from '../card-section/card-section.component';
-import { CardRowComponent } from '../card-row/card-row.component';
-import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component';
-import { CardTableComponent } from '../card-table/card-table.component';
-import { MockComponent } from 'ng-mocks';
-import { XrefsComponent } from '../xrefs/xrefs.component';
-import { CardGenericDocumentComponent } from '../card-generic-document/card-generic-document.component';
-
-
-describe('StudyCardComponent', () => {
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    class StudyCardComponentTester extends ComponentTester<StudyCardComponent> {
-        constructor() {
-            super(StudyCardComponent);
-        }
-
-        get title() {
-            return this.element('h3');
-        }
-
-        get cardHeader() {
-            return this.elements('div.card-header');
-        }
-
-        get studyInfo() {
-            return this.elements('div.col');
-        }
-
-        get map() {
-            return this.element('div #map');
-        }
-    }
-
-    const activatedRoute = fakeRoute({
-        params: of({ id: 's1' })
-    });
-
-    const source: DataDiscoverySource = {
-        '@id': 'src1',
-        '@type': ['schema:DataCatalog'],
-        'schema:name': 'source1',
-        'schema:url': 'srcUrl',
-        'schema:image': null
-    };
-
-    const location: BrapiResult<BrapiLocation> = {
-        metadata: null,
-        result: {
-            locationDbId: '1',
-            locationName: 'loc1',
-            locationType: 'Collecting site',
-            abbreviation: null,
-            countryCode: 'Fr',
-            countryName: 'France',
-            instituteAddress: null,
-            instituteName: 'Insti',
-            altitude: null,
-            latitude: null,
-            longitude: null,
-        }
-    };
-
-    const location2: BrapiResult<BrapiLocation> = {
-        metadata: null,
-        result: {
-            locationDbId: '2',
-            locationName: 'loc2',
-            locationType: 'Collecting site',
-            abbreviation: null,
-            countryCode: 'Fr',
-            countryName: 'France',
-            instituteAddress: null,
-            instituteName: 'Insti',
-            altitude: null,
-            latitude: 48.8534,
-            longitude: 2.3488,
-        }
-    };
-
-
-    const contacts: BrapiContacts = {
-        contactDbId: 'c1',
-        name: 'contact1',
-        email: 'contact1@email.com',
-        type: 'contact',
-        institutionName: 'Inst',
-    };
-
-    const searchStudy: BrapiResult<BrapiStudy> = {
-        metadata: null,
-        result: {
-            studyDbId: 's1',
-            studyType: 'phenotype',
-            studyName: 'study1',
-            studyDescription: null,
-            seasons: ['winter', '2019'],
-            startDate: '2018',
-            endDate: null,
-            active: true,
-            programDbId: 'p1',
-            programName: 'program1',
-            trialDbIds: ['10', '20'],
-            location: location.result,
-            locationDbId: '1',
-            locationName: 'loc1',
-            contacts: [contacts],
-            additionalInfo: null,
-            documentationURL: 'http://example.com/Study/s1',
-            dataLinks: [],
-            'schema:includedInDataCatalog': source
-        } as BrapiStudy
-    };
-
-    const trial1: BrapiResult<BrapiTrial> = {
-        metadata: null,
-        result: {
-            trialDbId: '10',
-            trialName: 'trial_10',
-            trialType: 'project',
-            active: true,
-            studies: [
-                { studyDbId: 's1', studyName: 'study1' },
-                { studyDbId: 's2', studyName: 'study2' }
-            ]
-
-        }
-    };
-    const trial2: BrapiResult<BrapiTrial> = {
-        metadata: null,
-        result: {
-            trialDbId: '20',
-            trialName: 'trial_20',
-            trialType: 'project',
-            active: true,
-            studies: [
-                { studyDbId: 's3', studyName: 'study3' },
-                { studyDbId: 's4', studyName: 'study4' }
-            ]
-
-        }
-    };
-    const osbVariable: BrapiResults<BrapiObservationVariable> = {
-        metadata: null,
-        result: {
-            data: [{
-                observationVariableDbId: 'var1',
-                contextOfUse: null,
-                institution: 'Insti',
-                crop: 'WoodyPlant',
-                name: 'varaiable1',
-                ontologyDbId: 'WPO',
-                ontologyName: 'Woody Plant Ontology',
-                synonyms: ['First synonym'],
-                language: 'EN',
-                trait: {
-                    traitDbId: 't1',
-                    name: 'trait1',
-                    description: null,
-                },
-                documentationURL: null,
-            }]
-        }
-    };
-
-    const germplasm: BrapiResults<BrapiGermplasm> = {
-        metadata: null,
-        result: {
-            data: [{
-                germplasmDbId: 'g1',
-                defaultDisplayName: 'germplam1',
-                accessionNumber: 'G_10',
-                germplasmName: 'germplam1',
-                germplasmPUI: 'urn_g1',
-                pedigree: null,
-                seedSource: 'Versaille Institute',
-                synonyms: null,
-                commonCropName: 'cheery',
-                instituteCode: '78',
-                instituteName: 'Versaille Institute',
-                biologicalStatusOfAccessionCode: null,
-                countryOfOriginCode: 'FR',
-                typeOfGermplasmStorageCode: null,
-                taxonIds: null,
-                genus: 'Populus',
-                species: 'x generosa',
-                speciesAuthority: 'Pop',
-                subtaxa: 'subsp',
-                subtaxaAuthority: '',
-                donors: null,
-                acquisitionDate: 'yesterday'
-            }, {
-                germplasmDbId: 'g2',
-                defaultDisplayName: 'germplam2',
-                accessionNumber: 'G_20',
-                germplasmName: 'germplam2',
-                germplasmPUI: 'urn_g2',
-                pedigree: null,
-                seedSource: 'Versaille Institute',
-                synonyms: null,
-                commonCropName: 'cheery',
-                instituteCode: '78',
-                instituteName: 'Versaille Institute',
-                biologicalStatusOfAccessionCode: null,
-                countryOfOriginCode: 'FR',
-                typeOfGermplasmStorageCode: null,
-                taxonIds: null,
-                genus: 'Triticum',
-                species: 'aestivum',
-                speciesAuthority: 'Trit',
-                subtaxa: 'subsp',
-                subtaxaAuthority: '',
-                donors: null,
-                acquisitionDate: 'today'
-            }],
-        }
-    };
-
-    const brapiService = jasmine.createSpyObj(
-        'BrapiService', [
-            'study',
-            'studyTrials',
-            'studyObservationVariables',
-            'studyGermplasms',
-            'location'
-        ]
-    );
-    brapiService.study.and.returnValue(of(searchStudy));
-    brapiService.studyTrials.withArgs('10').and.returnValue(of(trial1));
-    brapiService.studyTrials.withArgs('20').and.returnValue(of(trial2));
-    brapiService.studyObservationVariables.and.returnValue(of(osbVariable));
-    brapiService.studyGermplasms.and.returnValue(of(germplasm));
-    brapiService.location.withArgs('1').and.returnValue(of(location));
-    brapiService.location.withArgs('2').and.returnValue(of(location2));
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            imports: [RouterTestingModule],
-            declarations: [
-                StudyCardComponent, MapComponent, CardSectionComponent,
-                CardRowComponent, LoadingSpinnerComponent, CardTableComponent,
-                MockComponent(CardGenericDocumentComponent), MockComponent(XrefsComponent)
-            ],
-            providers: [
-                { provide: ActivatedRoute, useValue: activatedRoute },
-                { provide: BrapiService, useValue: brapiService }
-            ]
-        });
-    }));
-
-
-    it('should fetch the study data information but not display map', async(() => {
-        searchStudy.result.locationDbId = '1';
-        const tester = new StudyCardComponentTester();
-        const component = tester.componentInstance;
-        tester.detectChanges();
-
-        component.loaded.then(() => {
-            expect(component.study).toBeTruthy();
-            expect(component.location.locationDbId).toEqual('1');
-
-            tester.detectChanges();
-
-            expect(tester.map).toBeFalsy();
-            expect(tester.title).toContainText('Study phenotype: study1');
-
-            expect(tester.cardHeader[0]).toContainText('Identification');
-
-            expect(tester.studyInfo[0]).toContainText('study1');
-            expect(tester.studyInfo[1]).toContainText('s1');
-
-            expect(tester.cardHeader[1]).toContainText('Genotype');
-            expect(component.studyGermplasms.length).toEqual(2);
-
-            expect(tester.cardHeader[2]).toContainText('Variable');
-            expect(component.studyObservationVariables.length).toEqual(1);
-
-            expect(tester.cardHeader[3]).toContainText(' Data Set ');
-            expect(component.trialsIds.length).toEqual(2);
-            expect(component.studyDataset.length).toEqual(2);
-
-            expect(tester.cardHeader[4]).toContainText('Contact');
-        });
-    }));
-
-    it('should display map', async(() => {
-        searchStudy.result.locationDbId = '2';
-        const tester = new StudyCardComponentTester();
-        const component = tester.componentInstance;
-        tester.detectChanges();
-
-        component.loaded.then(() => {
-            expect(component.study).toBeTruthy();
-            expect(component.location.locationDbId).toEqual('2');
-
-            tester.detectChanges();
-
-            expect(tester.map).toBeTruthy();
-        });
-    }));
-});
diff --git a/frontend/src/app/study-card/study-card.component.ts b/frontend/src/app/study-card/study-card.component.ts
deleted file mode 100644
index 1fa0d7f5a42c6d1211c95a9ac547bbc8f3dd5e9a..0000000000000000000000000000000000000000
--- a/frontend/src/app/study-card/study-card.component.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { BrapiService } from '../brapi.service';
-import { ActivatedRoute } from '@angular/router';
-import { BrapiGermplasm, BrapiLocation, BrapiObservationVariable, BrapiStudy, BrapiTrial } from '../models/brapi.model';
-import { KeyValueObject, toKeyValueObjects } from '../utils';
-
-@Component({
-    selector: 'faidare-study-card',
-    templateUrl: './study-card.component.html',
-    styleUrls: ['./study-card.component.scss']
-})
-export class StudyCardComponent implements OnInit {
-
-    study: BrapiStudy;
-    studyGermplasms: BrapiGermplasm[];
-    studyObservationVariables: BrapiObservationVariable[];
-    additionalInfos: KeyValueObject[];
-    studyDataset: BrapiTrial[];
-    trialsIds: string[] = [];
-    location: BrapiLocation;
-    loading: boolean;
-    loaded: Promise<any>;
-
-    constructor(private brapiService: BrapiService, private route: ActivatedRoute) {
-    }
-
-    async ngOnInit() {
-        this.route.paramMap.subscribe(paramMap => {
-            this.loading = true;
-            const studyDbId = paramMap.get('id');
-
-            const study$ = this.brapiService.study(studyDbId).toPromise();
-            study$.then(studyResponse => {
-
-                this.study = studyResponse.result;
-                if (this.study.contacts) {
-                    this.study.contacts.sort((var1, var2) =>
-                        var1.name.localeCompare(var2.name));
-                }
-
-                this.additionalInfos = [];
-                if (this.study.additionalInfo) {
-                    this.additionalInfos = toKeyValueObjects(this.study.additionalInfo).sort();
-                }
-
-
-                // Get study trials
-                if (this.study.trialDbIds) {
-                    this.trialsIds = this.study.trialDbIds.sort();
-                }
-
-                this.studyDataset = [];
-                if (this.trialsIds && this.trialsIds !== []) {
-                    for (const trialsId of this.trialsIds) {
-                        this.brapiService.studyTrials(trialsId)
-                            .subscribe(trialResponse => {
-                                const trial = trialResponse.result;
-
-                                // Remove current study from trial studies
-                                trial.studies = trial.studies
-                                    .filter(study => study.studyDbId !== studyDbId);
-                                this.studyDataset.push(trial);
-                            });
-                    }
-                    if (this.studyDataset) {
-                        this.studyDataset.sort((var1, var2) =>
-                            var1.trialName.localeCompare(var2.trialName));
-                    }
-                }
-
-            });
-
-            study$.finally(() => {
-                if (this.study.locationDbId) {
-                    this.brapiService.location(this.study.locationDbId).subscribe(
-                        location => {
-                            this.location = location.result;
-                        });
-                }
-            });
-
-            this.studyObservationVariables = [];
-            const variable$ = this.brapiService.studyObservationVariables(studyDbId).toPromise();
-            variable$
-                .then(response => {
-                    this.studyObservationVariables = response.result.data.sort((var1, var2) =>
-                        var1.observationVariableDbId.localeCompare(var2.observationVariableDbId));
-                });
-
-            this.studyGermplasms = [];
-            const germplasm$ = this.brapiService.studyGermplasms(studyDbId).toPromise();
-            germplasm$
-                .then(studyGermplasm => {
-                    this.studyGermplasms = studyGermplasm.result.data.sort((var1, var2) =>
-                        var1.germplasmName.localeCompare(var2.germplasmName));
-                });
-
-
-            this.loaded = Promise.all([ study$, variable$, germplasm$ ]);
-            this.loaded.then(() => {
-                this.loading = false;
-            });
-        });
-
-    }
-}
diff --git a/frontend/src/app/utils.spec.ts b/frontend/src/app/utils.spec.ts
deleted file mode 100644
index 145bded094a9073464d69c9967dc25ada9205cc8..0000000000000000000000000000000000000000
--- a/frontend/src/app/utils.spec.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { KeyValueObject, removeNullUndefined, toKeyValueObjects } from './utils';
-
-
-describe('utils.toKeyValueObjects', () => {
-
-    it('should convert JS object to array of KeyValueObject', () => {
-        const actual = toKeyValueObjects({
-            'a': '1',
-            'b': '2',
-            'c': null,
-            'd': '',
-            '': 'e',
-            'f': '3'
-        });
-
-        const expected: KeyValueObject[] = [
-            { key: 'a', value: '1' },
-            { key: 'b', value: '2' },
-            { key: 'f', value: '3' },
-        ];
-
-        expect(actual).toEqual(expected);
-    });
-
-});
-
-describe('utils.removeNullUndefined', () => {
-
-    it('should remove undefined fields in object', () => {
-        const input = {
-            'a': undefined,
-            'b': 3,
-            'c': null,
-        };
-        const expected = {
-            'b': 3
-        };
-        const actual = removeNullUndefined(input);
-        expect(actual).toEqual(expected);
-    });
-
-});
diff --git a/frontend/src/app/utils.ts b/frontend/src/app/utils.ts
deleted file mode 100644
index 20bd4c0b2b2d468c73d25bd12323e441ae6bc0fa..0000000000000000000000000000000000000000
--- a/frontend/src/app/utils.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-export function asArray<T>(obj: T | T[]): T[] {
-    if (!obj) {
-        return null;
-    }
-    if (Array.isArray(obj)) {
-        return obj;
-    }
-    return [obj];
-}
-
-export interface KeyValueObject {
-    key: string;
-    value: string;
-}
-
-/**
- * Transform an object with string keys and values to a list of `KeyValueObject`.
- * Also makes sure the keys and values are truthy.
- */
-export function toKeyValueObjects(object: Record<string, string>): KeyValueObject[] {
-    return Object.entries(object)
-        .filter(([key, value]) => !!key && !!value)
-        .map(([key, value]) => ({ key, value }));
-}
-
-
-/**
- * Takes an object copies non null and non undefined field/value into a new object
- */
-export function removeNullUndefined(obj: Record<string, any>): Record<string, any> {
-    return Object.entries(obj)
-        .filter(([key, value]) => value !== undefined && value !== null)
-        .reduce((newObject, [key, value]) => {
-            newObject[key] = value;
-            return newObject;
-        }, {});
-}
diff --git a/frontend/src/app/xrefs/xrefs.component.html b/frontend/src/app/xrefs/xrefs.component.html
deleted file mode 100644
index a6bdbff8e7b0e37d2e6b26d0fbfe7df44369a036..0000000000000000000000000000000000000000
--- a/frontend/src/app/xrefs/xrefs.component.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<faidare-card-section *ngIf="xrefs.length > 0"
-                   header="Cross References">
-  <ng-template>
-    <div class="table-responsive scroll-big-table table-card-body">
-        <faidare-card-table
-          [headers]="[
-          'Name',
-          'Source',
-          'Type',
-          'Description'
-        ]"
-          [rows]=xrefs>
-          <ng-template let-crossRef>
-            <tr>
-              <td><a [href]="crossRef.url" target="_blank">{{ crossRef.name }}</a></td>
-              <td>{{ crossRef.database_name }}</td>
-              <td>{{ crossRef.entry_type }}</td>
-              <td>{{ crossRef.description | slice:0:120 }}...</td>
-            </tr>
-          </ng-template>
-        </faidare-card-table>
-    </div>
-  </ng-template>
-</faidare-card-section>
diff --git a/frontend/src/app/xrefs/xrefs.component.scss b/frontend/src/app/xrefs/xrefs.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/frontend/src/app/xrefs/xrefs.component.spec.ts b/frontend/src/app/xrefs/xrefs.component.spec.ts
deleted file mode 100644
index f09708ac219d67fcabfdd62ae1f5e20a92fd7f1b..0000000000000000000000000000000000000000
--- a/frontend/src/app/xrefs/xrefs.component.spec.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import { async, TestBed } from '@angular/core/testing';
-
-import { XrefsComponent } from './xrefs.component';
-import { ComponentTester, speculoosMatchers } from 'ngx-speculoos';
-import { XrefModel } from '../models/xref.model';
-import { of } from 'rxjs';
-import { GnpisService } from '../gnpis.service';
-import { CardSectionComponent } from '../card-section/card-section.component';
-import { CardTableComponent } from '../card-table/card-table.component';
-
-describe('XrefsComponent', () => {
-    beforeEach(() => jasmine.addMatchers(speculoosMatchers));
-
-    class XrefsComponentTester extends ComponentTester<XrefsComponent> {
-        constructor() {
-            super(XrefsComponent);
-        }
-
-        get cardHeader() {
-            return this.element('div.card-header');
-        }
-
-        get columns() {
-            return this.elements('td');
-        }
-    }
-
-    const gnpisService = jasmine.createSpyObj(
-        'GnpisService', [
-            'xref'
-        ]
-    );
-
-    const xref: XrefModel[] = [{
-        url: 'https://urgi.versailles.inra.fr/association/association/viewer.do#results/analysisIds=1808038',
-        description: 'Col-Fa-b*_MLM+Q+K is a GWASd anté paneCol-Fa-b*_MLM+Q+K is aGAS anlysis involving CC_Qualité' +
-            'djs dsqdsq djsqpodsjqodsqdsqkpdqpdWOLOLOLOOOOOOOsqpkdsqkdsqkdsqdsdsqdsqdsqddsqffjùsodfusjùfsfsd',
-        database_name: 'GnpIS',
-        entry_type: 'GWAS analysis',
-        db_version: 'GWAS_ANALYSIS_1808038_1',
-        name: 'Col-Fa-b*_MLM+Q+K'
-    }];
-
-
-    const xrefBlank: XrefModel[] = [];
-
-
-    beforeEach(async(() => {
-        TestBed.configureTestingModule({
-            declarations: [
-                XrefsComponent, CardSectionComponent, CardTableComponent
-            ],
-            providers: [
-                { provide: GnpisService, useValue: gnpisService },
-            ]
-        });
-    }));
-
-    it('should fetch the xref information', async(() => {
-        gnpisService.xref.and.returnValue(of(xref));
-        const tester = new XrefsComponentTester();
-
-        tester.detectChanges();
-
-        expect(tester.cardHeader).toContainText('Cross References');
-        expect(tester.columns[0]).toContainText(xref[0].name);
-        expect(tester.columns[1]).toContainText(xref[0].database_name);
-        expect(tester.columns[2]).toContainText(xref[0].entry_type);
-        expect(tester.columns[3].textContent.length).toBeLessThanOrEqual(124);
-
-    }));
-
-
-    it('should not display cross references', async(() => {
-        gnpisService.xref.and.returnValue(of(xrefBlank));
-        const tester = new XrefsComponentTester();
-        tester.detectChanges();
-
-        expect(tester.cardHeader).toBeFalsy();
-
-    }));
-});
diff --git a/frontend/src/app/xrefs/xrefs.component.ts b/frontend/src/app/xrefs/xrefs.component.ts
deleted file mode 100644
index d63a97f361706e7cee5e8c03994ffaf932b4b686..0000000000000000000000000000000000000000
--- a/frontend/src/app/xrefs/xrefs.component.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import { GnpisService } from '../gnpis.service';
-import { XrefModel } from '../models/xref.model';
-
-@Component({
-    selector: 'faidare-xrefs',
-    templateUrl: './xrefs.component.html',
-    styleUrls: ['./xrefs.component.scss']
-})
-export class XrefsComponent implements OnInit {
-
-    xrefs: Array<XrefModel> = new Array<XrefModel>();
-    @Input() xrefId: string;
-
-    constructor(private gnpisService: GnpisService) {
-    }
-
-    ngOnInit() {
-        this.gnpisService.xref(this.xrefId).subscribe(
-            xrefs => {
-                this.xrefs = xrefs;
-            }
-        );
-    }
-}
diff --git a/frontend/src/assets/faidare/ABOUT.md b/frontend/src/assets/faidare/ABOUT.md
deleted file mode 100644
index a1daa9927d99974feb930f3252ae86d14e4e5fd5..0000000000000000000000000000000000000000
--- a/frontend/src/assets/faidare/ABOUT.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# About this data portal
-
-The purpose of this portal is to facilitate the discoverability of public data on plant biology from a federation of established data repositories.
-
-It is based on the [Breeding API (BrAPI)](https://brapi.org/) specifications and facilitates the access to genotype and phenotype datasets for crop and forest plants through an easy to use web interface.
-It also provides a standard interface that can be accessed programatically through [web services](https://urgi.versailles.inra.fr/faidare/swagger-ui.html).
-
-It is an extension of the generic [Data-Discovery portal](https://forgemia.inra.fr/urgi-is/data-discovery), a web portal that allows finding any type of data across several databases through a lightweight keyword based search.
-FAIDARE offers more detailed search and data retrieval capabilities and it takes advantage of the growing adoption of the BrAPI. 
-
-It has been developed by [INRA-URGI](http://urgi.versailles.inra.fr/) in collaboration with [**Elixir Plant**](https://elixir-europe.org/communities/plant-sciences), [**Phenome-Emphasis.fr**](https://www.phenome-emphasis.fr/phenome_eng/Methodological-projects/MCP2-Distributed-Information-system) and [**Elixir-fr/IFB**](https://www.france-bioinformatique.fr).
-
-If you want to join the FAIDARE federation, please read the "Join us" section and [contact us](mailto:urgi-contact@inra.fr?subject=%5BFAIDARE%5D).
diff --git a/frontend/src/assets/faidare/HELP.md b/frontend/src/assets/faidare/HELP.md
deleted file mode 100644
index d6240d00a17de2c066722365acfc19c01c23d1e7..0000000000000000000000000000000000000000
--- a/frontend/src/assets/faidare/HELP.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# Help section
-
-> Note: this application is responsive, meaning that its rendering will adapt to the screen's size of your device, hence location of items below can be different than stated.
-
-You can find data by building your own query using the fields available in the two tabs of the form:
-* The `Germplasm` tab allow you to add criteria on plant material/germplasm (_e.g._ its name, genus or species).
-* The `Trait` tab allow you to add criteria on trait(s) and/or variable(s) name(s).
-
-In each field, one or several term(s) can be entered.
-As you begin to type, a list of relevant suggestions is proposed to guide you in your search.
-
-The query is launched as soon as at least one parameter is selected in the form.
-The results are automatically updated if a parameter is added or removed.
-
-To refine your search, you can add more specific filters by using the facets/categories on the left side.
-> Note: applying several filters in the same facet/category will search for documents related to any of the selected terms (resulting in a `OR` operator between all the category's terms).
-> In contrary, applying filters in different facets/categories will search for documents having both filters (resulting in an `AND` operator for the different facets).
diff --git a/frontend/src/assets/faidare/HOW-TO-JOIN.md b/frontend/src/assets/faidare/HOW-TO-JOIN.md
deleted file mode 100644
index 4c9843e23b05a35cced150e06f38d1260509cb80..0000000000000000000000000000000000000000
--- a/frontend/src/assets/faidare/HOW-TO-JOIN.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# How to join FAIDARE federation?
-
-If you want your information system to be part of the FAIDARE federation, we invite you to [contact us](mailto:urgi-contact@inra.fr?subject=%5BFAIDARE%5D) as soon as possible so that we can follow your progress and assist you if needed.
-
-You will need to create a new `source` corresponding to your information system.
-For this, you will have to set up your own [BrAPI](https://brapi.org/) endpoint and reference it in the sources of [Elixir's FAIDARE harvester](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis).
-
-General information and considerations can be found on the [Elixir Plant](https://elixir-europe.org/communities/plant-sciences) web page.
-
-## Creation of a BrAPI endpoint
-To create a new endpoint, you should implement the BrAPI calls needed to give access to the data of your information system.
-Those calls are documented in various formats on the [Developer resources](https://www.brapi.org/developers#) section of the BrAPI web site.
-
-The BrAPI calls currently used by FAIDARE are:
-* germplasm
-* location
-* ontology
-* program
-* study
-* study/{studyDbId}/observationVariable
-* study/{studyDbId}/germplasm
-* study/{studyDbId}/observationUnit (can be resource intensive and therefore not implemented)
-* trial
-
-> Note that since the tool makes a backlink to your information system, we need a URL in the `DocumentationURL` field of the BrAPI for researchers to get more detailed information about the indexed entry directly in your information system.
-
-To ensure the quality of your BrAPI endpoint, you can use the validation tools provided by the BrAPI community, especially [Brava](http://webapps.ipk-gatersleben.de/brapivalidator/).
-
-If you have any question or need help implementing BrAPI calls, you can [contact the BrAPI community](https://brapi.org/).
-
-## Referencement of a BrAPI endpoint
-For your endpoint to be visible on FAIDARE, you have to declare it in the sources of [Elixir's FAIDARE harvester](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis).
-To do this, you only have to create your own configuration file, according to the following template, and add it to the [`sources`](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis/tree/master/sources) directory of the harvester:
-```
-{
-  "@context": {
-    "schema": "http://schema.org/",
-    "brapi": "https://brapi.org/"
-  },
-  "@type": "schema:DataCatalog",
-  "@id": "[information system URL]",
-  "schema:identifier": "[BrAPI endpoint name]",
-  "schema:name": "[information system name]",
-  "brapi:endpointUrl": "[BrAPI endpoint URL]"
-}
-```
-Example: [URGI.json](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis/blob/master/sources/URGI.json)
-```
-{
-  "@context": {
-    "schema": "http://schema.org/",
-    "brapi": "https://brapi.org/"
-  },
-  "@type": "schema:DataCatalog",
-  "@id": "https://urgi.versailles.inra.fr/gnpis",
-  "schema:identifier": "URGI",
-  "schema:name": "URGI GnpIS",
-  "brapi:endpointUrl": "https://urgi.versailles.inra.fr/faidare/brapi/v1/"
-}
-```
-
-If you have any question or need help referencing your endpoint, you can [contact us](mailto:urgi-contact@inra.fr?subject=%5BFAIDARE%5D).
-
-## Data availability & update
-[Elixir's FAIDARE harvester](https://github.com/elixir-europe/plant-brapi-etl-data-lookup-gnpis) extract the metadata available from all declared sources (_i.e._ BrAPI endpoint) and index it into a centralised Elasticsearch cache.
-The sources are reindexed regularly (once a month maximum) but if you want a reindexation following a major update on your side, please [inform us](mailto:urgi-contact@inra.fr?subject=%5BFAIDARE%5D).
diff --git a/frontend/src/assets/faidare/LEGAL-MENTIONS.md b/frontend/src/assets/faidare/LEGAL-MENTIONS.md
deleted file mode 100644
index 21aa25f5359596345684b6786ca40e46de74b8ca..0000000000000000000000000000000000000000
--- a/frontend/src/assets/faidare/LEGAL-MENTIONS.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# General Terms of Use
-
-By browsing this web site, you acknowledge and accept its general terms of use described below.
-
-## Intellectual property
-
-Except where otherwise noted, content on this site is licensed under a [Creative Commons Attribution 4.0 International license](https://creativecommons.org/licenses/by/4.0/).
-
-The logo is the property of INRAE and you are not allowed to re-use it for your own work and purpose.
-
-## Content
-
-The portal is maintained by URGI, an INRAE unit, and its [Data Management Plan (DOI: 10.15454/9HM5UI)](https://doi.org/10.15454/9HM5UI) has been defined in the frame of the [Plant Bioinformatics Facility (PlantBioinfoPF, DOI: 10.15454/1.5572414581735654E12)](https://doi.org/10.15454/1.5572414581735654E12) that hosts the portal.
-
-Access to this web site can be interrupted at any time and without prior warning in case of force majeure.
-In case of a planned service interruption, users will be notified in advance by the editor as far as possible.
-
-The portal allows to find public data across a federation of databases.
-The licences associated to data are therefore defined by the institutes in charge of them.
-
-The portal links to external web sites.
-INRAE does not take responsibility of the content of these web site.
-
-Users are sole responsible for the searches they carry out, as well as for the interpretation and for the use they make of the results.
-
-Users are informed that their use of the results should not infringe on current legislation or the recommendations of the French Data Protection Authority (CNIL) with respect to personal data.
-Users are warned that the information must be used for strictly professional purposes only and downloading screen shots in order to constitute or enrich a database is contrary to French law and therefore forbidden, as is its use for commercial or advertising purposes (CNIL).
-
-The portal may give access to personal and professional data concerning technical and scientific actors in relation with the data.
-This information helps to identify and acknowledge the authors of the scientific works.
-This personal information is attached to the produced datasets and follows the data life cycle.
- 
-## Personal data
-
-Technical data (date, hour, IP address of the computer of the visitor, pages viewed) are collected only for the statistical analysis of the usage of the portal.
-These data are kept confidential and not transmitted to any other party.
-They are stored on INRA’s private servers for 5 years.
-
-During visits on URGI web site and its hosted applications, a cookie can be automatically installed on visitor’s web browsers to retrieve statistics on the pages that are visited and support improvements of the services provided by the web site.
-Visitors can configure their web browsers in order to be informed of the setting of cookies and refuse them.
-
-According to the European Regulation on the protection of personal data (EU Regulation 2016/679), you have the right to access, rectify, oppose and delete information about yourself.
-If you wish to exercise this right and obtain information about yourself, please contact us:
-- By [email](mailto:urgi-contact@inra.fr?subject=%5BData%20Discovery%5D%20GPDR%20request)
-- Or via any other way available on our [contact form](https://urgi.versailles.inra.fr/Contact-us)
-
-## Modifications
-
-The editor might change the terms of use and user’s rights without prior warning.
-
-Last update: 2021 February 22th
diff --git a/frontend/src/assets/faidare/applicationLogo.png b/frontend/src/assets/faidare/applicationLogo.png
deleted file mode 100644
index 0a8aa7ebcd17afde597ea938d3d106680a2f0f98..0000000000000000000000000000000000000000
Binary files a/frontend/src/assets/faidare/applicationLogo.png and /dev/null differ
diff --git a/frontend/src/assets/faidare/elixir_logo.png b/frontend/src/assets/faidare/elixir_logo.png
deleted file mode 100644
index 723f989aff5ad9f5d6da4c31ada0f39e58344afa..0000000000000000000000000000000000000000
Binary files a/frontend/src/assets/faidare/elixir_logo.png and /dev/null differ
diff --git a/frontend/src/assets/faidare/images/question-mark.png b/frontend/src/assets/faidare/images/question-mark.png
deleted file mode 100644
index 87fbdf4294ddba32291fdcae056a7c0f9cef793c..0000000000000000000000000000000000000000
Binary files a/frontend/src/assets/faidare/images/question-mark.png and /dev/null differ
diff --git a/frontend/src/assets/faidare/theme.scss b/frontend/src/assets/faidare/theme.scss
deleted file mode 100644
index c2f6f8680c5e812e89f1be916da6db54fd336de0..0000000000000000000000000000000000000000
--- a/frontend/src/assets/faidare/theme.scss
+++ /dev/null
@@ -1,93 +0,0 @@
-// non-public variables used in this theme only
-$_theme-black: #222222;
-$_theme-blue: #0f6e9f;
-$_theme-light-gray: #eaeaea;
-$_theme-gray: #c2c2c2;
-
-$component-active-bg: $_theme-blue;
-
-// override default link colors
-$link-color: lighten($_theme-blue, 0.4);
-$link-hover-color: $_theme-black;
-
-// override default shadows behavior
-$enable-shadows: true;
-
-
-@import "~bootstrap/scss/functions";
-@import "~bootstrap/scss/variables";
-@import "~bootstrap/scss/mixins";
-@import "~bootstrap/scss/tables";
-@import "~bootstrap/scss/card";
-@import "~bootstrap/scss/transitions";
-@import "~bootstrap/scss/tooltip";
-@import "~bootstrap/scss/popover";
-
-
-// public custom variables used in this theme, and in component styles
-
-//custom tables
-.table {
-  table-layout: fixed;
-
-  thead {
-    background-color: #0f6191;
-  }
-
-}
-
-.popover {
-  max-width: 100%;
-}
-
-/*table th, table td { overflow: hidden; }*/
-
-.imagePopover {
-  max-width: fit-content;
-}
-
-.scroll {
-  display: block;
-  max-height: 200px;
-  overflow-y: auto;
-  -ms-overflow-style: -ms-autohiding-scrollbar;
-}
-
-.back-form-button {
-  top: 0;
-  right: 0;
-  position: fixed;
-  z-index: 1100;
-  margin-top: 8px;
-  margin-right: 100px;
-}
-
-h4 {
-  color: #0f6191;
-}
-
-.ellipsis {
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-// custom button
-$theme-btn-color: $white;
-$theme-btn-bg-color: $_theme-black;
-$theme-btn-border-color: $_theme-black;
-$theme-btn-hover-color: $white;
-$theme-btn-hover-bg-color: $_theme-blue;
-$theme-btn-hover-border-color: $_theme-blue;
-
-// custom navbar
-$theme-navbar-height: 4rem;
-$theme-navbar-color: $black;
-$theme-navbar-bg-color: $_theme-light-gray;
-$theme-navbar-hover-color: $white;
-$theme-navbar-hover-bg-color: $_theme-gray;
-
-// custom footer
-$theme-footer-height: 3rem;
-$theme-footer-color: $black;
-$theme-footer-bg-color: $_theme-light-gray;
-
diff --git a/frontend/src/browserslist b/frontend/src/browserslist
deleted file mode 100644
index fcb53f03c06b54833f0094c21de3c7f949ca5e2b..0000000000000000000000000000000000000000
--- a/frontend/src/browserslist
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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 remove 'not' from the last line of the file and adjust as needed
-
-> 0.5%
-last 2 versions
-Firefox ESR
-not dead
-IE 9-11
diff --git a/frontend/src/custom-bootstrap.scss b/frontend/src/custom-bootstrap.scss
deleted file mode 100644
index 8e759073f440303c3674330db9fac30b6ac23a97..0000000000000000000000000000000000000000
--- a/frontend/src/custom-bootstrap.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-@import "~bootstrap/scss/root";
-@import "~bootstrap/scss/reboot";
-@import "~bootstrap/scss/type";
-@import "~bootstrap/scss/images";
-// @import "~bootstrap/scss/code";
-@import "~bootstrap/scss/grid";
-// @import "~bootstrap/scss/tables";
-@import "~bootstrap/scss/forms";
-@import "~bootstrap/scss/buttons";
-@import "~bootstrap/scss/transitions";
-@import "~bootstrap/scss/dropdown";
-// @import "~bootstrap/scss/button-group";
-@import "~bootstrap/scss/input-group";
-// @import "~bootstrap/scss/custom-forms";
-@import "~bootstrap/scss/nav";
-@import "~bootstrap/scss/navbar";
-@import "~bootstrap/scss/card";
-// @import "~bootstrap/scss/breadcrumb";
-@import "~bootstrap/scss/pagination";
-@import "~bootstrap/scss/badge";
-// @import "~bootstrap/scss/jumbotron";
-@import "~bootstrap/scss/alert";
-// @import "~bootstrap/scss/progress";
-// @import "~bootstrap/scss/media";
-// @import "~bootstrap/scss/list-group";
-// @import "~bootstrap/scss/close";
-// @import "~bootstrap/scss/modal";
-@import "~bootstrap/scss/tooltip";
-// @import "~bootstrap/scss/popover";
-// @import "~bootstrap/scss/carousel";
-@import "~bootstrap/scss/utilities";
-// @import "~bootstrap/scss/print";
diff --git a/frontend/src/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts
deleted file mode 100644
index 8b30554b7bfcb14d8c820f9f12edd73271ac2310..0000000000000000000000000000000000000000
--- a/frontend/src/environments/environment.prod.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-
-export const environment = {
-    production: false,
-    appTitle: 'FAIR Data-finder for Agronomic REsearch',
-    navbar: {
-        name: 'FAIDARE',
-        title: 'FAIR Data-finder for Agronomic REsearch',
-        logo: 'assets/applicationLogo.png',
-        links: [
-            {
-                label: 'URGI',
-                url: '#',
-                subMenu: [
-                    { label: 'Home', url: 'https://urgi.versailles.inra.fr' },
-                    { label: 'News', url: 'https://urgi.versailles.inra.fr/About-us/News' },
-                    { label: 'About us', url: 'https://urgi.versailles.inra.fr/About-us' }
-                ]
-            }
-        ],
-        contributor: {
-            name: 'Elixir',
-            url: 'https://elixir-europe.org/',
-            logo: 'assets/elixir_logo.png'
-        }
-    },
-    helpMdFile: 'assets/HELP.md',
-    aboutUsMdFile: 'assets/ABOUT.md',
-    joinUsMdFile: 'assets/HOW-TO-JOIN.md',
-    legalMentionsMdFile: 'assets/LEGAL-MENTIONS.md',
-    taxaLinks: {
-        NCBI: 'https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=',
-        ThePlantList: 'http://www.theplantlist.org/tpl1.1/record/',
-        TAXREF: 'https://inpn.mnhn.fr/espece/cd_nom/',
-        CatalogueOfLife: 'http://www.catalogueoflife.org/col/details/species/id/'
-    }
-};
diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts
deleted file mode 100644
index 91c34aa9bdd61710e101113961b084ae7f78f5ca..0000000000000000000000000000000000000000
--- a/frontend/src/environments/environment.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-// This file can be replaced during build by using the `fileReplacements` array.
-// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
-// The list of file replacements can be found in `angular.json`.
-
-export const environment = {
-    production: false,
-    appTitle: 'FAIR Data-finder for Agronomic REsearch',
-    navbar: {
-        name: 'FAIDARE',
-        title: 'FAIR Data-finder for Agronomic REsearch',
-        logo: 'assets/applicationLogo.png',
-        links: [
-            {
-                label: 'URGI',
-                url: '#',
-                subMenu: [
-                    { label: 'Home', url: 'https://urgi.versailles.inra.fr' },
-                    { label: 'News', url: 'https://urgi.versailles.inra.fr/About-us/News' },
-                    { label: 'About us', url: 'https://urgi.versailles.inra.fr/About-us' }
-                ]
-            }
-        ],
-        contributor: {
-            name: 'Elixir',
-            url: 'https://elixir-europe.org/',
-            logo: 'assets/elixir_logo.png'
-        }
-    },
-    helpMdFile: 'assets/HELP.md',
-    aboutUsMdFile: 'assets/ABOUT.md',
-    joinUsMdFile: 'assets/HOW-TO-JOIN.md',
-    legalMentionsMdFile: 'assets/LEGAL-MENTIONS.md',
-    taxaLinks: {
-        NCBI: 'https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=',
-        ThePlantList: 'http://www.theplantlist.org/tpl1.1/record/',
-        TAXREF: 'https://inpn.mnhn.fr/espece/cd_nom/',
-        CatalogueOfLife: 'http://www.catalogueoflife.org/col/details/species/id/'
-    }
-};
-
-/*
- * For easier debugging in development mode, you can import the following file
- * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
- *
- * This import should be commented out in production mode because it will have a negative impact
- * on performance if an error is thrown.
- */
-// import 'zone.js/dist/zone-error';  // Included with Angular CLI.
diff --git a/frontend/src/favicon.ico b/frontend/src/favicon.ico
deleted file mode 100644
index 8081c7ceaf2be08bf59010158c586170d9d2d517..0000000000000000000000000000000000000000
Binary files a/frontend/src/favicon.ico and /dev/null differ
diff --git a/frontend/src/index.html b/frontend/src/index.html
deleted file mode 100644
index 4f9431d72739dbc532c81dd2f49e81732cd1688b..0000000000000000000000000000000000000000
--- a/frontend/src/index.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!doctype html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <title>FAIDARE</title>
-    <base href="./">
-
-    <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link rel="icon" type="image/x-icon" href="assets/favicon.ico">
-    <script src="https://code.iconify.design/1/1.0.7/iconify.min.js"></script>
-  </head>
-  <body>
-    <faidare-root></faidare-root>
-  </body>
-</html>
diff --git a/frontend/src/karma.conf.js b/frontend/src/karma.conf.js
deleted file mode 100644
index 495fcc2c4cc1304b8c4e861f656c7cb857764c7b..0000000000000000000000000000000000000000
--- a/frontend/src/karma.conf.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Karma configuration file, see link for more information
-// https://karma-runner.github.io/1.0/config/configuration-file.html
-
-module.exports = function (config) {
-    config.set({
-        basePath: '',
-        frameworks: ['jasmine', '@angular-devkit/build-angular'],
-        plugins: [
-            require('karma-jasmine'),
-            require('karma-chrome-launcher'),
-            require('karma-firefox-launcher'),
-            require('karma-jasmine-html-reporter'),
-            require('karma-coverage-istanbul-reporter'),
-            require('karma-junit-reporter'),
-            require('@angular-devkit/build-angular/plugins/karma')
-        ],
-        client: {
-            clearContext: false // leave Jasmine Spec Runner output visible in browser
-        },
-        coverageIstanbulReporter: {
-            dir: require('path').join(__dirname, '../coverage'),
-            reports: ['html', 'lcovonly', 'text-summary'],
-            fixWebpackSourcePaths: true
-        },
-        reporters: ['progress', 'kjhtml', 'junit'],
-        junitReporter: {
-            outputDir: '../karma-junit-tests-report', // results will be saved as $outputDir/$browserName.xml
-            outputFile: undefined, // if included, results will be saved as $outputDir/$browserName/$outputFile
-            suite: '', // suite will become the package name attribute in xml testsuite element
-            useBrowserName: true, // add browser name to report and classes names
-            nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element
-            classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element
-            properties: {}, // key value pair of properties to add to the <properties> section of the report
-            xmlVersion: null // use '1' if reporting to be per SonarQube 6.2 XML format
-        },
-        port: 9876,
-        colors: true,
-        logLevel: config.LOG_INFO,
-        autoWatch: true,
-        browsers: ['ChromeHeadlessNoSandbox'],
-        customLaunchers: {
-            ChromeHeadlessNoSandbox: {
-                base: 'ChromeHeadless',
-                flags: ['--no-sandbox'] // required for Gitlab CI
-            }
-        },
-        captureTimeout: 1200000, // increase timeouts: https://github.com/jasmine/jasmine/issues/1413#issuecomment-334247097
-        browserNoActivityTimeout: 120000,
-        singleRun: false,
-        restartOnFileChange: true
-    });
-};
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
deleted file mode 100644
index 9d9067c6f5bcd2f079db5e554dd44e39d04d1bd5..0000000000000000000000000000000000000000
--- a/frontend/src/main.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { enableProdMode } from '@angular/core';
-import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
-
-import { AppModule } from './app/app.module';
-import { environment } from './environments/environment';
-
-if (environment.production) {
-    enableProdMode();
-}
-
-platformBrowserDynamic().bootstrapModule(AppModule)
-    .catch(err => console.error(err));
diff --git a/frontend/src/polyfills.ts b/frontend/src/polyfills.ts
deleted file mode 100644
index 99d6df5edd029ecd914adb26b81ed7ca73bdf561..0000000000000000000000000000000000000000
--- a/frontend/src/polyfills.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * This file includes polyfills needed by Angular and is loaded before the app.
- * You can add your own extra polyfills to this file.
- *
- * This file is divided into 2 sections:
- *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
- *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
- *      file.
- *
- * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
- * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
- * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
- *
- * Learn more in https://angular.io/guide/browser-support
- */
-
-/***************************************************************************************************
- * BROWSER POLYFILLS
- */
-
-
-/** IE9, IE10, IE11, and Chrome <55 polyfills are now automatically handled with the
- * `"es5BrowserSupport": true` property in `angular.json`
- * See https://blog.ninja-squad.com/2019/01/31/angular-cli-7.3/
- */
-
-/***************************************************************************************************
- * Zone JS is required by default for Angular itself.
- */
-import 'zone.js/dist/zone'; // Included with Angular CLI.
-
-/** IE10 and IE11 requires the following for NgClass support on SVG elements */
-// import 'classlist.js';  // Run `npm install --save classlist.js`.
-
-/**
- * Web Animations `@angular/platform-browser/animations`
- * 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
- * because those flags need to be set before `zone.js` being loaded, and webpack
- * will put import in the top of bundle, so user need to create a separate file
- * in this directory (for example: zone-flags.ts), and put the following flags
- * into that file, and then add the following code before importing zone.js.
- * import './zone-flags.ts';
- *
- * The flags allowed in zone-flags.ts are listed here.
- *
- * The following flags will work for all browsers.
- *
- * (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;
- *
- */
-
-/***************************************************************************************************
- * APPLICATION IMPORTS
- */
diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss
deleted file mode 100644
index a0804b179bb02466f0d46db3ceac691b7cbcc46c..0000000000000000000000000000000000000000
--- a/frontend/src/styles.scss
+++ /dev/null
@@ -1,96 +0,0 @@
-$fa-font-path: '~font-awesome/fonts';
-
-@import '~font-awesome/scss/font-awesome';
-@import 'theme';
-@import 'custom-bootstrap';
-
-.dropdown-item.active {
-  .text-muted {
-    color: $white !important;
-  }
-}
-
-.card-section-body {
-  border: 2px solid rgb(195, 214, 226);
-  border-top-width: 0px;
-  border-bottom-left-radius: 0.25rem;
-  border-bottom-right-radius: 0.25rem;
-}
-
-.table-card-body {
-  padding: 0;
-  border: 2px solid rgb(195, 214, 226);
-  border-top-width: 0px;
-  border-bottom-left-radius: 0.25rem;
-  border-bottom-right-radius: 0.25rem;
-}
-
-.row-sep {
-  border-top: 1px solid #f0f0f0;
-}
-
-.row-sep .row-sep:first-of-type {
-  border: none;
-}
-
-.content-overflow {
-  max-height: 200px;
-  overflow-y: auto;
-}
-
-.content-overflow-big {
-  max-height: 275px;
-  overflow: auto;
-}
-.scroll-table {
-  max-height: 200px;
-  overflow-y: auto;
-}
-
-.scroll-big-table {
-  max-height: 500px;
-  overflow-y: auto;
-}
-
-.display-spinner-front {
-  position: absolute;
-  top: 70px;
-  left: 720px;
-  background-color: #F9F9F9;
-}
-
-.popover {
-  width: 100%;
-  max-width: 500px;
-}
-
-.mt-custom {
-  margin-top: 75px;
-}
-
-h1 {
-  border-bottom: solid;
-  font-weight: bold;
-  color: #0f6191;
-  margin-bottom: 20px;
-}
-
-h2 {
-  border-bottom: solid;
-  color: #0f6191;
-  margin-bottom: 16px;
-}
-
-h3 {
-  font-weight: bold;
-  color: #0f6191;
-}
-
-blockquote {
-  border-left-style: solid;
-  border-left-width: 3px;
-  color: grey;
-  padding-left: 5px;
-  margin-left: 16px;
-  font-style: italic;
-}
diff --git a/frontend/src/test.ts b/frontend/src/test.ts
deleted file mode 100644
index 4e7f1a5bbd2509e91148e8f1fd5b918ca1ee2499..0000000000000000000000000000000000000000
--- a/frontend/src/test.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// This file is required by karma.conf.js and loads recursively all the .spec and framework files
-
-import 'zone.js/dist/zone-testing';
-import { getTestBed } from '@angular/core/testing';
-import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
-
-declare const require: any;
-
-// First, initialize the Angular testing environment.
-getTestBed().initTestEnvironment(
-    BrowserDynamicTestingModule,
-    platformBrowserDynamicTesting()
-);
-// Then we find all the tests.
-const context = require.context('./', true, /\.spec\.ts$/);
-// And load the modules.
-context.keys().map(context);
diff --git a/frontend/src/tsconfig.app.json b/frontend/src/tsconfig.app.json
deleted file mode 100644
index 32ee8c7b851f6b01a578ccd5fc501cc4d650e3c5..0000000000000000000000000000000000000000
--- a/frontend/src/tsconfig.app.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "extends": "../tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../out-tsc/app",
-    "types": [
-      "leaflet",
-      "leaflet.markercluster"
-    ]
-  },
-  "exclude": [
-    "test.ts",
-    "**/*.spec.ts"
-  ]
-}
diff --git a/frontend/src/tsconfig.spec.json b/frontend/src/tsconfig.spec.json
deleted file mode 100644
index de7733630eb224b246854a20934f792051926e8f..0000000000000000000000000000000000000000
--- a/frontend/src/tsconfig.spec.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "extends": "../tsconfig.json",
-  "compilerOptions": {
-    "outDir": "../out-tsc/spec",
-    "types": [
-      "jasmine",
-      "node"
-    ]
-  },
-  "files": [
-    "test.ts",
-    "polyfills.ts"
-  ],
-  "include": [
-    "**/*.spec.ts",
-    "**/*.d.ts"
-  ]
-}
diff --git a/frontend/src/tslint.json b/frontend/src/tslint.json
deleted file mode 100644
index 33e8c3101e737a40e795ae9e8c0c5e2fdb7766ec..0000000000000000000000000000000000000000
--- a/frontend/src/tslint.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "extends": "../tslint.json",
-  "rules": {
-    "directive-selector": [
-      true,
-      "attribute",
-      "faidare",
-      "camelCase"
-    ],
-    "component-selector": [
-      true,
-      "element",
-      "faidare",
-      "kebab-case"
-    ],
-    "template-cyclomatic-complexity": [
-      true,
-      13
-    ]
-  }
-}
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
deleted file mode 100644
index 62f2590c355bc2ea92b5afceb2726d70dcafc244..0000000000000000000000000000000000000000
--- a/frontend/tsconfig.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "compileOnSave": false,
-  "compilerOptions": {
-    "baseUrl": "./",
-    "importHelpers": true,
-    "outDir": "./dist/out-tsc",
-    "sourceMap": true,
-    "declaration": false,
-    "module": "es2015",
-    "moduleResolution": "node",
-    "emitDecoratorMetadata": true,
-    "experimentalDecorators": true,
-    "target": "es5",
-    "typeRoots": [
-      "node_modules/@types"
-    ],
-    "lib": [
-      "es2018",
-      "dom"
-    ]
-  }
-}
diff --git a/frontend/tslint.json b/frontend/tslint.json
deleted file mode 100644
index f6e323348ffc55fb409b8f94a9e38a2042788e03..0000000000000000000000000000000000000000
--- a/frontend/tslint.json
+++ /dev/null
@@ -1,172 +0,0 @@
-{
-  "rulesDirectory": [
-    "codelyzer",
-    "node_modules/tslint-eslint-rules/dist/rules"
-  ],
-  "rules": {
-    "arrow-return-shorthand": true,
-    "ban-comma-operator": true,
-    "callable-types": true,
-    "class-name": true,
-    "comment-format": [
-      true,
-      "check-space"
-    ],
-    "curly": true,
-    "deprecation": {
-      "severity": "warn"
-    },
-    "eofline": true,
-    "forin": true,
-    "import-blacklist": true,
-    "import-spacing": true,
-    "indent": [
-      true,
-      "spaces",
-      4
-    ],
-    "ter-indent": [
-      true,
-      4
-    ],
-    "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-constant-condition": true,
-    "no-construct": true,
-    "no-debugger": true,
-    "no-duplicate-imports": true,
-    "no-duplicate-super": true,
-    "no-duplicate-switch-case": true,
-    "no-dynamic-delete": true,
-    "no-empty": false,
-    "no-empty-interface": true,
-    "no-eval": true,
-    "no-implicit-dependencies": [
-      true,
-      "dev"
-    ],
-    "no-import-side-effect": [
-      true,
-      {
-        "ignore-module": "(core-js/.*|zone\\.js/.*)$"
-      }
-    ],
-    "no-inferrable-types": [
-      true,
-      "ignore-params"
-    ],
-    "no-redundant-jsdoc": true,
-    "no-misused-new": true,
-    "no-non-null-assertion": true,
-    "no-parameter-reassignment": true,
-    "no-return-await": true,
-    "no-shadowed-variable": true,
-    "no-string-literal": false,
-    "no-string-throw": true,
-    "no-switch-case-fall-through": true,
-    "no-this-assignment": 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,
-    "object-curly-spacing": true,
-    "one-line": [
-      true,
-      "check-open-brace",
-      "check-catch",
-      "check-else",
-      "check-whitespace"
-    ],
-    "prefer-const": true,
-    "prefer-while": true,
-    "quotemark": [
-      true,
-      "single"
-    ],
-    "radix": true,
-    "semicolon": [
-      true,
-      "always",
-      "ignore-bound-class-methods"
-    ],
-    "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"
-    ],
-    "angular-whitespace": [
-      true,
-      "check-semicolon",
-      "check-interpolation",
-      "check-pipe"
-    ],
-    "banana-in-box": true,
-    "component-class-suffix": true,
-    "contextual-life-cycle": true,
-    "directive-class-suffix": true,
-    "enforce-component-selector": true,
-    "no-conflicting-life-cycle-hooks": true,
-    "no-input-rename": true,
-    "no-output-on-prefix": true,
-    "no-output-rename": true,
-    "template-conditional-complexity": true,
-    "template-cyclomatic-complexity": [
-      true,
-      11
-    ],
-    "templates-no-negated-async": true,
-    "use-host-property-decorator": true,
-    "use-input-property-decorator": true,
-    "use-life-cycle-interface": true,
-    "use-output-property-decorator": true,
-    "use-pipe-transform-interface": true,
-    "use-view-encapsulation": false
-  }
-}
diff --git a/gradle.properties b/gradle.properties
index a8e36b70f17e40417e1bfcdac9b96ae165820188..8b137891791fe96927ad78e64b0aad7bded08bdc 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,9 +1 @@
-# gradle.properties
 
-systemProp.sonar.sources=frontend/src
-systemProp.sonar.language=typescript
-systemProp.sonar.scm.provider=git
-systemProp.sonar.typescript.tsconfigPath=frontend/tsconfig.json
-systemProp.sonar.javascript.lcov.reportPaths=frontend/coverage/lcov.info
-systemProp.sonar.nodejs.executable=/tmp/node/node
-systemProp.sonar.typescript.exclusions=**/*.spec.ts
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 457aad0d98108420a977756b7145c93c8910b076..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 75b8c7c8c67a003599a36935d1c6a41519fc2207..00e33edef6936b1ada8721cff42201db8c9d8675 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index af6708ff229fda75da4f7cc4da4747217bac4d53..1b6c787337ffb79f0e3cf8b1e9f00f680a959de1 100755
--- a/gradlew
+++ b/gradlew
@@ -1,78 +1,129 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m"'
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
+
 # Determine the Java command to use to start the JVM.
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -89,84 +140,95 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
 fi
 
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
 
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
     # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
         fi
-        i=$((i+1))
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
     done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
-  cd "$(dirname "$0")"
-fi
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
 
 exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 6d57edc706c93465988754383a2d7ff353d4e79f..107acd32c4e687021ef32db511e8a206129b88ec 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
 @if "%DEBUG%" == "" @echo off
 @rem ##########################################################################
 @rem
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m"
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
 
 @rem Find java.exe
 if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
 set JAVA_HOME=%JAVA_HOME:"=%
 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@ echo location of your Java installation.
 
 goto fail
 
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
 :execute
 @rem Setup the command line
 
 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
+
 @rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
 
 :end
 @rem End local scope for the variables with windows NT shell
diff --git a/scripts/harvest.sh b/scripts/harvest.sh
index 7f8672e4784179d5cf5ce8ab14def43b8d3eb267..564d94ad1ba36f7878fbabecc72d910deaab06f9 100755
--- a/scripts/harvest.sh
+++ b/scripts/harvest.sh
@@ -7,10 +7,9 @@ ES_PORT="9200"
 ENV="dev"
 DOCUMENT_TYPES="all"
 
-ALL_DOCUMENT_TYPES="germplasm germplasmMcpd germplasmAttribute germplasmPedigree germplasmProgeny location program study trial observationUnit datadiscovery"
+ALL_DOCUMENT_TYPES="germplasm germplasmMcpd germplasmAttribute germplasmPedigree germplasmProgeny location program study trial observationUnit xref"
 ALL_ENVS="dev beta staging int prod test"
-BASEDIR=$(dirname "$0")
-TMP_FILE="log.tmp"
+BASEDIR=$(readlink -f "$(dirname $0)")
 
 RED='\033[0;31m'
 GREEN='\033[0;32m'
@@ -79,7 +78,7 @@ while [ -n "$1" ]; do
 		-h|--help) help;;
 		-v|--verbose) VERBOSE=1;shift 1;;
 		--debug) set -x;shift 1;;
-		-jsonDir) DATA_DIR="$2"; shift 2;;
+		-jsonDir) DATA_DIR="$(readlink -f $2)"; shift 2;;
 		-es_host) ES_HOST="$2"; shift 2;;
 		-es_port) ES_PORT="$2"; shift 2;;
 		-env) ENV="$2"; shift 2;;
@@ -113,11 +112,6 @@ for DOCUMENT_TYPE in ${DOCUMENT_TYPES}; do
 	fi
 done
 
-# Compress JSON files
-for FILE in $(find "${DATA_DIR}" -name "*.json"); do
-	gzip "$FILE"
-done
-
 LOG_DIR="${DATA_DIR%/}/indexing-log"
 
 if [[ -d ${LOG_DIR} ]]
@@ -125,22 +119,27 @@ then
     rm -r "${LOG_DIR}"
 fi
 
-export ES_HOST ES_PORT INDEX_NAME LOG_DIR
+TMP_FILE="/tmp/bulk/log.tmp"
+[ -f "$TMP_FILE" ] && rm -f "$TMP_FILE"
+
+OUTDIR="/tmp/bulk/${INDEX_NAME}"
+[ -d "$OUTDIR" ] && rm -rf "$OUTDIR"
+mkdir -p "$OUTDIR"
 
-process_file() {
-    file=$(basename "$1")
-    logfile="${file%.*}.log.gz"
-    source=$(basename "$(dirname "$1")")
+export ES_HOST ES_PORT INDEX_NAME LOG_DIR OUTDIR BASEDIR
 
-    if ! [[ -d "${LOG_DIR}/$source" ]]
-    then
-        mkdir -p "${LOG_DIR}/$source"
-    fi
 
-    curl -s -H 'Content-Type: application/x-ndjson' -H 'Content-Encoding: gzip' -H 'Accept-Encoding: gzip' -XPOST "${ES_HOST}:${ES_PORT}/${INDEX_NAME}/_bulk" --data-binary @"$1" > "${LOG_DIR}/$source/$logfile"
+index_resources() {
+    SOURCE=$(basename $(dirname "$1"))
+    bash -c "set -o pipefail; gunzip -c $1 \
+            | jq -c -f ${BASEDIR}/to_bulk.jq 2> ${OUTDIR}/${SOURCE}-$2.jq.err \
+            | gzip -c \
+            | curl -s -H 'Content-Type: application/x-ndjson' -H 'Content-Encoding: gzip' -H 'Accept-Encoding: gzip' \
+               -XPOST \"${ES_HOST}:${ES_PORT}/${INDEX_NAME}/_bulk\"\
+               --data-binary '@-' 2> ${OUTDIR}/${SOURCE}-$2.jq.err  > ${OUTDIR}/${SOURCE}-$2-resources.log.gz "
 }
 
-export -f process_file
+export -f index_resources
 
 for DOCUMENT_TYPE in ${DOCUMENT_TYPES}; do
 	echo && echo -e "${BOLD}Manage ${DOCUMENT_TYPE} documents...${NC}"
@@ -163,13 +162,16 @@ for DOCUMENT_TYPE in ${DOCUMENT_TYPES}; do
 	INDEX_NAME="${INDEX_PATTERN}-d"$(date +%s)
 	echo -e "* Index documents into ${ES_HOST}:${ES_PORT}/${INDEX_NAME} indice..."
 	{
-		parallel -j 2 --bar process_file ::: $(find "${DATA_DIR}" -name "${DOCUMENT_TYPE}-*.json.gz")
-	} || {
-		code=$?
-		echo -e "${RED}ERROR: a problem occurred when trying to index data with parallel program.${NC}"
-		exit $code
+		parallel -j 4 --bar index_resources {1} {1/.} ::: "$(find "${DATA_DIR}" -name "${DOCUMENT_TYPE}-*.json.gz")"
 	}
-	parallel "gunzip -c {} | jq '.errors' | grep -q true && echo -e '${ORANGE}ERROR found in {}${NC}' >> ${TMP_FILE} ;" ::: $(find "${DATA_DIR}" -name "${DOCUMENT_TYPE}-*.log.gz")
+
+	# check all JQ err files...
+    FILES_IN_ERROR=$(find "${OUTDIR}" -size "+0" -name "*${DOCUMENT_TYPE}*jq.err")
+    [ -n "${FILES_IN_ERROR}" ] && { echo -e "${RED}ERROR: some problems occured with JQ processing, look at files:${ORANGE} ${FILES_IN_ERROR}${NC}" ; exit 4 ; }
+
+    parallel "gunzip -c {} | jq '.errors' | grep -q true && echo -e '${ORANGE}ERROR found in {}${NC}' >> ${TMP_FILE} ;" ::: "$(find "${OUTDIR}" -name "*${DOCUMENT_TYPE}-*.log.gz")"
+    parallel "gunzip -c {} | jq '.error' | grep -q true && echo -e '${ORANGE}ERROR related to data found when indexing {}${NC}' >> ${TMP_FILE} ;" ::: ${OUTDIR}/*${DOCUMENT_TYPE}*-resources.log.gz
+    parallel "gunzip -c {} | jq '.error? | length == 0' | grep -q false && echo -e '${ORANGE}ERROR related to Elasticsearch API usage found when indexing {}${NC}' >> ${TMP_FILE} ;" ::: ${OUTDIR}/*${DOCUMENT_TYPE}*-resources.log.gz
 	if [ -f "${TMP_FILE}" ] && [ -s "${TMP_FILE}" ]; then
 		echo -e "${RED}ERROR: a problem occurred when trying to index data into ${ES_HOST}:${ES_PORT}/${INDEX_NAME} indice.${NC}"
 		echo -e "${ORANGE}$(cat ${TMP_FILE})${NC}"
@@ -177,28 +179,28 @@ for DOCUMENT_TYPE in ${DOCUMENT_TYPES}; do
 		exit 1;
 	fi
 
-	# Check indexed data
-	echo -e "* Check data indexed from ${DATA_DIR} into ${INDEX_NAME}..."
-	# skip some documents because they contain nested objects that distort the count
-	if [[ "${DOCUMENT_TYPE}" != "germplasmAttribute" && "${DOCUMENT_TYPE}" != "observationUnit" && "${DOCUMENT_TYPE}" != "datadiscovery" ]]; then
-		COUNT_EXTRACTED_DOCS=0
-		for FILE in $(find ${DATA_DIR} -name "${DOCUMENT_TYPE}-*.json.gz"); do
-			COUNT_FILE_DOCS=$(zcat ${FILE} | grep "\"_id\"" | sort | uniq | wc -l)
-			COUNT_EXTRACTED_DOCS=$((COUNT_EXTRACTED_DOCS+COUNT_FILE_DOCS))
-		done
-		curl -s -XGET "${ES_HOST}:${ES_PORT}/${INDEX_NAME}/_refresh" >/dev/null
-		COUNT_INDEXED_DOCS=$(curl -s -XGET "${ES_HOST}:${ES_PORT}/_cat/indices/${INDEX_NAME}?h=docs.count")
-	fi
-	if [ "$COUNT_INDEXED_DOCS" != "$COUNT_EXTRACTED_DOCS" ]; then
-		echo -e "${RED}ERROR: a problem occurred when indexing data from ${DATA_DIR} on FAIDARE ${ENV}.${NC}"
-		echo -e "${ORANGE}Expected ${COUNT_EXTRACTED_DOCS} documents but got ${COUNT_INDEXED_DOCS} indexed documents.${NC}"
-		exit 1;
-	fi
-	sleep 5
+    # Check indexed data
+    echo -e "* Check data indexed from ${DATA_DIR} into ${INDEX_NAME}..."
+    	# skip some documents because they contain nested objects that distort the count
+    	if [[ "${DOCUMENT_TYPE}" != "germplasmAttribute" && "${DOCUMENT_TYPE}" != "trial" && "${DOCUMENT_TYPE}" != "xref" ]]; then
+    		COUNT_EXTRACTED_DOCS=0
+    		for FILE in $(find ${DATA_DIR} -name "${DOCUMENT_TYPE}-*.json.gz"); do
+    			COUNT_FILE_DOCS=$(gunzip -c ${FILE} | grep -o "\"@id\"" | wc -l)
+    			COUNT_EXTRACTED_DOCS=$((COUNT_EXTRACTED_DOCS+COUNT_FILE_DOCS))
+    		done
+    		curl -s -XGET "${ES_HOST}:${ES_PORT}/${INDEX_NAME}/_refresh" >/dev/null
+    		COUNT_INDEXED_DOCS=$(curl -s -XGET "${ES_HOST}:${ES_PORT}/_cat/indices/${INDEX_NAME}?h=docs.count")
+    	fi
+    	if [ "$COUNT_INDEXED_DOCS" != "$COUNT_EXTRACTED_DOCS" ]; then
+    		echo -e "${RED}ERROR: a problem occurred when indexing data from ${DATA_DIR} on FAIDARE ${ENV}.${NC}"
+    		echo -e "${ORANGE}Expected ${COUNT_EXTRACTED_DOCS} documents but got ${COUNT_INDEXED_DOCS} indexed documents.${NC}"
+    		exit 1;
+    	fi
+    	sleep 5
 
 	# Add aliases
 	ALIAS_PATTERN="${INDEX_PATTERN}-group*"
-	ALIAS_EXIST=$(curl -s -XGET "${ES_HOST}:${ES_PORT}/_alias/${ALIAS_PATTERN}" | jq '.status' | grep -q "404" && echo "false" || echo "true")
+	ALIAS_EXIST=$(curl -s -XGET "${ES_HOST}:${ES_PORT}/_alias/${ALIAS_PATTERN}" | jq '.status' | grep -q -e "404" -e 'null' && echo "false" || echo "true")
 	if [ "${ALIAS_EXIST}" == "true" ]; then
 		echo -e "* Delete aliases ${ALIAS_PATTERN}..."
 		LOG=$(curl -s -XDELETE "${ES_HOST}:${ES_PORT}/*/_aliases/${ALIAS_PATTERN}")
@@ -219,8 +221,8 @@ for DOCUMENT_TYPE in ${DOCUMENT_TYPES}; do
 	}
 }' | jq -cr '.aggregations.uniq_group.buckets[].key') # Extract ES aggregation bucket keys
 	[ -z "$GROUP_IDS" ] && {
-		echo -e "${RED}ERROR: could not list 'groupId' values from index.${NC}"
-		exit 1;
+		echo -e "${ORANGE}WARNING: could not list 'groupId' values from index. Defaulting to 'groupId' = 0. ${NC}"
+		GROUP_IDS="0"
 	}
 	echo -e "* Create aliases:"
 	for GROUP_ID in ${GROUP_IDS}; do
diff --git a/scripts/to_bulk.jq b/scripts/to_bulk.jq
new file mode 100644
index 0000000000000000000000000000000000000000..cef91fc15cc5327b92ef390f0bda7c3eb5bfbcab
--- /dev/null
+++ b/scripts/to_bulk.jq
@@ -0,0 +1,28 @@
+#!/usr/bin/env jq -Mf
+
+# Transforms a JSON array of documents in Elasticsearch compliant bulk file
+# using value of 'ID_FIELD' variable if provided, or using concatenation of
+# several fields, as the Elasticsearch documents identifier
+# The input data must be of type 'JSON array'.
+# Return codes:
+#   - 0 if process succeeded
+#   - 2 if the input is not a JSON array
+
+def to_string:
+    if ((. | type) == "array") then
+        .|join("|")|tostring
+    else
+        .|tostring
+    end
+    | if(. == "null" or . == null) then
+        ""
+    else
+        .
+    end
+;
+
+def to_bulk:
+    .[] | . |= {"index":  {"_type": "_doc", "_id": ."@id" }}, .
+;
+
+to_bulk
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 4bd5a482217fc2c6b3921cafc0bdb602ebd96641..b8faef34872a40284f74d8be029e0dd7861df5d7 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,2 +1,2 @@
 rootProject.name = "faidare"
-include("backend", "frontend")
+include("backend", "web")
diff --git a/web/build.gradle.kts b/web/build.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..fd9828917cea4449637f247dbf3542b930a20016
--- /dev/null
+++ b/web/build.gradle.kts
@@ -0,0 +1,41 @@
+import com.github.gradle.node.yarn.task.YarnInstallTask
+import com.github.gradle.node.yarn.task.YarnTask
+
+plugins {
+    base
+    id("com.github.node-gradle.node") version "3.2.1"
+}
+
+node {
+    version.set("16.14.0")
+    npmVersion.set("6.14.10")
+    yarnVersion.set("1.22.17")
+    download.set(true)
+}
+
+tasks {
+    npmInstall {
+        enabled = false
+    }
+
+    val prepare by registering {
+        dependsOn(YarnInstallTask.NAME)
+    }
+
+    // This is not a yarn_build task because the task to run is `yarn build:prod`
+    // and tasks with colons are not supported
+    val yarnBuildProd by registering(YarnTask::class) {
+        args.set(listOf("run", "build:prod"))
+        dependsOn(prepare)
+        inputs.file("webpack.config.js")
+        inputs.file("tsconfig.json")
+        inputs.file("package.json")
+        inputs.file("yarn.lock")
+        inputs.dir("src")
+        outputs.dir("$buildDir/dist")
+    }
+
+    assemble {
+        dependsOn(yarnBuildProd)
+    }
+}
diff --git a/web/package.json b/web/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d940af62f9ba163d5f8fa70ea296821a16bfb0bc
--- /dev/null
+++ b/web/package.json
@@ -0,0 +1,50 @@
+{
+  "name": "faidaire-web",
+  "version": "1.0.0",
+  "description": "",
+  "private": true,
+  "scripts": {
+    "build": "webpack --mode development",
+    "build:prod": "webpack --mode production",
+    "watch": "webpack --mode development --watch",
+    "watch:prod": "webpack --mode production --watch",
+    "test": "echo \"Error: no test specified\" && exit 1",
+    "format": "prettier --write \"src/**/*.+(ts|js|json|html|scss)\"",
+    "format:backend-templates": "prettier --write ../backend/src/main/resources/templates"
+  },
+  "author": "",
+  "license": "MIT",
+  "dependencies": {
+    "@types/leaflet": "1.7.9",
+    "bootstrap": "5.1.3",
+    "leaflet": "1.7.1"
+  },
+  "devDependencies": {
+    "@types/bootstrap": "5.1.9",
+    "@types/leaflet.markercluster": "1.4.6",
+    "autoprefixer": "10.4.2",
+    "clean-webpack-plugin": "4.0.0",
+    "css-loader": "6.7.1",
+    "css-minimizer-webpack-plugin": "3.4.1",
+    "leaflet.markercluster": "1.5.3",
+    "mini-css-extract-plugin": "2.6.0",
+    "postcss": "8.4.8",
+    "postcss-loader": "6.2.1",
+    "prettier": "2.5.1",
+    "sass": "1.49.9",
+    "sass-loader": "12.6.0",
+    "ts-loader": "9.2.7",
+    "typescript": "4.6.2",
+    "webpack": "5.70.0",
+    "webpack-cli": "4.9.2"
+  },
+  "browserslist": [
+    "defaults"
+  ],
+  "prettier": {
+    "printWidth": 140,
+    "singleQuote": true,
+    "arrowParens": "avoid",
+    "trailingComma": "none"
+  }
+}
diff --git a/web/src/bootstrap/popovers.ts b/web/src/bootstrap/popovers.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4e6baa5bbdd271604c328bd0167729290c6b0f97
--- /dev/null
+++ b/web/src/bootstrap/popovers.ts
@@ -0,0 +1,19 @@
+import Popover from 'bootstrap/js/dist/popover';
+
+export function initializePopovers() {
+    const popoverTriggerList: Array<HTMLElement> = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
+    popoverTriggerList.forEach(popoverTriggerEl => {
+        const options: Partial<Popover.Options> = {};
+        const contentSelector = popoverTriggerEl.dataset.bsElement;
+        if (contentSelector) {
+            const content = document.querySelector(contentSelector);
+            if (content) {
+                options.content = content.innerHTML;
+                options.html = true;
+            } else {
+                throw new Error('element with selector ' + contentSelector + ' not found');
+            }
+        }
+        return new Popover(popoverTriggerEl, options);
+    });
+}
diff --git a/web/src/index.ts b/web/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..18fd98fd9580fd50269bf100a160d93660172a7e
--- /dev/null
+++ b/web/src/index.ts
@@ -0,0 +1,9 @@
+import { initializePopovers } from './bootstrap/popovers';
+import { initializeMap } from './map/map';
+import 'bootstrap/js/dist/dropdown';
+import 'bootstrap/js/dist/collapse';
+
+(window as any).faidare = {
+    initializePopovers,
+    initializeMap
+};
diff --git a/web/src/map/map.ts b/web/src/map/map.ts
new file mode 100644
index 0000000000000000000000000000000000000000..37cf126de97c3655f243e2a832b0ba0f7ba38544
--- /dev/null
+++ b/web/src/map/map.ts
@@ -0,0 +1,91 @@
+import * as L from 'leaflet';
+import 'leaflet.markercluster';
+
+interface MapLocation {
+    locationDbId: string;
+    locationType: 'Origin site' | 'Collecting site' | 'Evaluation site' | null;
+    locationName: string;
+    latitude: number;
+    longitude: number;
+}
+
+interface MapOptions {
+    contextPath: string;
+    locations: Array<MapLocation>;
+}
+
+function markerColor(location: MapLocation) {
+    switch (location.locationType) {
+        case 'Origin site':
+            return 'red';
+        case 'Collecting site':
+            return 'blue';
+        case 'Evaluation site':
+            return 'green';
+    }
+    return 'purple';
+}
+
+function markerIconUrl(contextPath: string, location: MapLocation) {
+    return `${contextPath}/resources/images/marker-icon-${markerColor(location)}.png`;
+}
+
+export function initializeMap(options: MapOptions) {
+    if (!options.locations.length) {
+        return;
+    }
+
+    const mapContainerElement = document.querySelector('#map-container');
+    mapContainerElement!.classList.remove('d-none');
+    const mapElement = document.querySelector('#map') as HTMLElement;
+    const map = L.map(mapElement);
+    L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
+        attribution:
+            'Tiles &copy; Esri &mdash; Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, ' +
+            'Esri China (Hong Kong), Esri (Thailand), TomTom, 2012'
+    }).addTo(map);
+
+    const firstLocation = options.locations[0];
+    map.setView([firstLocation.latitude, firstLocation.longitude], 5);
+
+    const markers = L.markerClusterGroup();
+    const mapMarkers: Array<L.Marker> = [];
+    for (const location of options.locations) {
+        const icon = L.icon({
+            iconUrl: markerIconUrl(options.contextPath, location),
+            iconAnchor: [12, 41] // point of the icon which will correspond to marker's location
+        });
+
+        const popupElement = document.createElement('div');
+
+        const titleElement = document.createElement('strong');
+        titleElement.innerText = location.locationName;
+        popupElement.appendChild(titleElement);
+        popupElement.appendChild(document.createElement('br'));
+
+        if (location.locationType) {
+            const typeElement = document.createElement('span');
+            typeElement.innerText = location.locationType;
+            popupElement.appendChild(typeElement);
+            popupElement.appendChild(document.createElement('br'));
+        }
+
+        const linkElement = document.createElement('a');
+        linkElement.innerText = 'Details';
+        linkElement.href = `${options.contextPath}/sites/${location.locationDbId}`;
+        popupElement.appendChild(linkElement);
+
+        const marker = L.marker([location.latitude, location.longitude], { icon: icon });
+        markers.addLayer(marker.bindPopup(popupElement));
+        mapMarkers.push(marker);
+    }
+    const initialZoom = map.getZoom();
+
+    map.fitBounds(L.featureGroup(mapMarkers).getBounds());
+    const markerZoom = map.getZoom();
+
+    setTimeout(() => {
+        map.setZoom(Math.min(initialZoom, markerZoom));
+        map.addLayer(markers);
+    }, 100);
+}
diff --git a/web/src/style/_custom-bootstrap.scss b/web/src/style/_custom-bootstrap.scss
new file mode 100644
index 0000000000000000000000000000000000000000..9de7c3dce4b8fbea20fd88c39b1bc001c72b69a0
--- /dev/null
+++ b/web/src/style/_custom-bootstrap.scss
@@ -0,0 +1,53 @@
+/*!
+ * Bootstrap v5.1.0 (https://getbootstrap.com/)
+ * Copyright 2011-2021 The Bootstrap Authors
+ * Copyright 2011-2021 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+
+// scss-docs-start import-stack
+// Configuration
+@import '~bootstrap/scss/functions';
+@import '~bootstrap/scss/variables';
+@import '~bootstrap/scss/mixins';
+@import '~bootstrap/scss/utilities';
+
+// Layout & components
+@import '~bootstrap/scss/root';
+@import '~bootstrap/scss/reboot';
+@import '~bootstrap/scss/type';
+@import '~bootstrap/scss/images';
+@import '~bootstrap/scss/containers';
+@import '~bootstrap/scss/grid';
+@import '~bootstrap/scss/tables';
+// @import '~bootstrap/scss/forms';
+@import '~bootstrap/scss/buttons';
+@import '~bootstrap/scss/transitions';
+@import '~bootstrap/scss/dropdown';
+// @import '~bootstrap/scss/button-group';
+@import '~bootstrap/scss/nav';
+@import '~bootstrap/scss/navbar';
+@import '~bootstrap/scss/card';
+// @import '~bootstrap/scss/accordion';
+// @import '~bootstrap/scss/breadcrumb';
+// @import '~bootstrap/scss/pagination';
+// @import '~bootstrap/scss/badge';
+// @import '~bootstrap/scss/alert';
+// @import '~bootstrap/scss/progress';
+// @import '~bootstrap/scss/list-group';
+// @import '~bootstrap/scss/close';
+// @import '~bootstrap/scss/toasts';
+// @import '~bootstrap/scss/modal';
+// @import '~bootstrap/scss/tooltip';
+@import '~bootstrap/scss/popover';
+// @import '~bootstrap/scss/carousel';
+// @import '~bootstrap/scss/spinners';
+// @import '~bootstrap/scss/offcanvas';
+// @import '~bootstrap/scss/placeholders';
+
+// Helpers
+// @import '~bootstrap/scss/helpers';
+
+// Utilities
+@import '~bootstrap/scss/utilities/api';
+// scss-docs-end import-stack
diff --git a/web/src/style/style.scss b/web/src/style/style.scss
new file mode 100644
index 0000000000000000000000000000000000000000..806a0d4bec25eee291369e323e27f2c77d0d3fe1
--- /dev/null
+++ b/web/src/style/style.scss
@@ -0,0 +1,91 @@
+$headings-color: #0f6191;
+$border-color: #0f6e9f;
+$link-color: #0f6fa1;
+$link-decoration: none;
+$link-hover-decoration: underline;
+$enable-shadows: true;
+$table-border-color: #dee2e6;
+$table-group-separator-color: $table-border-color;
+
+@import 'custom-bootstrap';
+@import '~leaflet/dist/leaflet.css';
+@import '~leaflet.markercluster/dist/MarkerCluster.css';
+@import '~leaflet.markercluster/dist/MarkerCluster.Default.css';
+
+a[role='button'] {
+  color: $link-color !important;
+}
+
+.f-row {
+  border-top: 1px solid $gray-300;
+  padding: 0.5rem 0;
+  .label {
+    font-weight: 700;
+  }
+}
+
+.f-card {
+  border: 1px solid $border-color;
+  border-radius: 0.25rem;
+  margin: 0.5rem 0;
+  h2 {
+    font-size: $h4-font-size;
+    padding: 0.5rem 1rem;
+    background-image: repeating-linear-gradient(#0f96cd, #0f6191, #0f76a5);
+    color: $white;
+  }
+  .f-card-body {
+    padding: 0.25rem 1rem;
+    .f-row:first-of-type {
+      border-top: 0;
+    }
+  }
+}
+
+.popover {
+  max-width: min(80vw, 500px);
+}
+
+.popover-header {
+  font-weight: 700;
+}
+
+#map {
+  height: min(400px, 60vh);
+}
+
+.map-legend img {
+  height: 1.5rem;
+}
+
+.content-overflow {
+  max-height: 200px;
+  overflow-y: auto;
+  overflow-x: hidden;
+  &.content-overflow-big {
+    max-height: 275px;
+  }
+}
+
+.scroll-table-container {
+  max-height: 200px;
+  overflow-y: auto;
+  padding-top: 0;
+  &.scroll-table-container-big {
+    max-height: 500px;
+  }
+}
+
+.table-sticky {
+  width: 100%;
+  thead th {
+    position: sticky;
+    position: -webkit-sticky;
+    top: 0;
+    background-color: white;
+    border-top-width: 0;
+    th {
+      padding-top: 0;
+    }
+  }
+}
diff --git a/web/tsconfig.json b/web/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..f29e7eaa843ed56163538ea8fb4c9c8c2968f4a1
--- /dev/null
+++ b/web/tsconfig.json
@@ -0,0 +1,72 @@
+{
+  "compilerOptions": {
+    /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+    /* Basic Options */
+    // "incremental": true,                         /* Enable incremental compilation */
+    "target": "es2015",                                /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
+    "module": "es2015",                             /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
+    // "lib": [],                                   /* Specify library files to be included in the compilation. */
+    // "allowJs": true,                             /* Allow javascript files to be compiled. */
+    // "checkJs": true,                             /* Report errors in .js files. */
+    // "jsx": "preserve",                           /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
+    // "declaration": true,                         /* Generates corresponding '.d.ts' file. */
+    // "declarationMap": true,                      /* Generates a sourcemap for each corresponding '.d.ts' file. */
+    // "sourceMap": true,                           /* Generates corresponding '.map' file. */
+    // "outFile": "./",                             /* Concatenate and emit output to single file. */
+    // "outDir": "./",                              /* Redirect output structure to the directory. */
+    // "rootDir": "./",                             /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
+    // "composite": true,                           /* Enable project compilation */
+    // "tsBuildInfoFile": "./",                     /* Specify file to store incremental compilation information */
+    // "removeComments": true,                      /* Do not emit comments to output. */
+    // "noEmit": true,                              /* Do not emit outputs. */
+    // "importHelpers": true,                       /* Import emit helpers from 'tslib'. */
+    // "downlevelIteration": true,                  /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
+    // "isolatedModules": true,                     /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+
+    /* Strict Type-Checking Options */
+    "strict": true,                                 /* Enable all strict type-checking options. */
+    // "noImplicitAny": true,                       /* Raise error on expressions and declarations with an implied 'any' type. */
+    // "strictNullChecks": true,                    /* Enable strict null checks. */
+    // "strictFunctionTypes": true,                 /* Enable strict checking of function types. */
+    // "strictBindCallApply": true,                 /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
+    // "strictPropertyInitialization": true,        /* Enable strict checking of property initialization in classes. */
+    // "noImplicitThis": true,                      /* Raise error on 'this' expressions with an implied 'any' type. */
+    // "alwaysStrict": true,                        /* Parse in strict mode and emit "use strict" for each source file. */
+
+    /* Additional Checks */
+    // "noUnusedLocals": true,                      /* Report errors on unused locals. */
+    // "noUnusedParameters": true,                  /* Report errors on unused parameters. */
+    // "noImplicitReturns": true,                   /* Report error when not all code paths in function return a value. */
+    // "noFallthroughCasesInSwitch": true,          /* Report errors for fallthrough cases in switch statement. */
+    // "noUncheckedIndexedAccess": true,            /* Include 'undefined' in index signature results */
+    // "noImplicitOverride": true,                  /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
+    // "noPropertyAccessFromIndexSignature": true,  /* Require undeclared properties from index signatures to use element accesses. */
+
+    /* Module Resolution Options */
+    // "moduleResolution": "node",                  /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+    // "baseUrl": "./",                             /* Base directory to resolve non-absolute module names. */
+    // "paths": {},                                 /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+    // "rootDirs": [],                              /* List of root folders whose combined content represents the structure of the project at runtime. */
+    // "typeRoots": [],                             /* List of folders to include type definitions from. */
+    // "types": [],                                 /* Type declaration files to be included in compilation. */
+    // "allowSyntheticDefaultImports": true,        /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+    "esModuleInterop": true,                        /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+    // "preserveSymlinks": true,                    /* Do not resolve the real path of symlinks. */
+    // "allowUmdGlobalAccess": true,                /* Allow accessing UMD globals from modules. */
+
+    /* Source Map Options */
+    // "sourceRoot": "",                            /* Specify the location where debugger should locate TypeScript files instead of source locations. */
+    // "mapRoot": "",                               /* Specify the location where debugger should locate map files instead of generated locations. */
+    // "inlineSourceMap": true,                     /* Emit a single file with source maps instead of having a separate file. */
+    // "inlineSources": true,                       /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
+
+    /* Experimental Options */
+    // "experimentalDecorators": true,              /* Enables experimental support for ES7 decorators. */
+    // "emitDecoratorMetadata": true,               /* Enables experimental support for emitting type metadata for decorators. */
+
+    /* Advanced Options */
+    "skipLibCheck": true,                           /* Skip type checking of declaration files. */
+    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
+  }
+}
diff --git a/web/webpack.config.js b/web/webpack.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..2606ec0d1bbe919808215eb1ed51b2b6320da35b
--- /dev/null
+++ b/web/webpack.config.js
@@ -0,0 +1,75 @@
+const path = require('path');
+const { CleanWebpackPlugin } = require('clean-webpack-plugin');
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
+
+module.exports = (env, argv) => ({
+    context: path.resolve(__dirname, '.'),
+    // inline source maps only in development mode
+    devtool: argv.mode === 'production' ? undefined : 'inline-source-map',
+    plugins: [
+        // allows extracting the CSS into a CSS file instead of bundling it in a JS file
+        new MiniCssExtractPlugin({
+            filename: argv.mode === 'production' ? '[name].[contenthash].css' : '[name].css'
+        }),
+        // cleans the output directory before each build
+        new CleanWebpackPlugin({
+            // and the empty, useless style.js after each build
+            protectWebpackAssets: false,
+            cleanAfterEveryBuildPatterns: ['style*.js']
+        })
+    ],
+    entry: {
+        // a JS bundle is generated for the index.ts entry point. Since the application is really small
+        // and does not have much JavaScript logic, a single bundle is sufficient
+        script: './src/index.ts',
+        // A CSS bundle is generated for the style.scss entry point.
+        style: './src/style/style.scss'
+    },
+    module: {
+        rules: [
+            {
+                test: /\.tsx?$/,
+                use: 'ts-loader',
+                exclude: /node_modules/,
+            },
+            {
+                // .scss files are loaded by the sass-loader, which transforms them into css loaded by the css-loader
+                // which are then bundled into a css file by the MiniCssExtractPlugin loader
+                test: /\.scss$/i,
+                use: [
+                    MiniCssExtractPlugin.loader,
+                    'css-loader',
+                    'sass-loader',
+                    {
+                        loader: "postcss-loader",
+                        options: {
+                            postcssOptions: {
+                                plugins: ["autoprefixer",],
+                            },
+                        },
+                    }
+                ],
+            },
+        ],
+    },
+    resolve: {
+        // our files are .ts files, but libraries are bundled in .js files
+        extensions: ['.ts', '.js'],
+    },
+    output: {
+        // the output is stored in build/dist/resources
+        path: path.resolve(__dirname, 'build/dist/resources'),
+        filename: argv.mode === 'production' ? '[name].[contenthash].js' : '[name].js'
+    },
+    optimization: {
+        minimizer: [
+            '...',
+            new CssMinimizerPlugin()
+        ]
+    },
+    performance: {
+        maxAssetSize: 300000,
+        maxEntrypointSize: 300000
+    }
+});
diff --git a/web/yarn.lock b/web/yarn.lock
new file mode 100644
index 0000000000000000000000000000000000000000..00732305b51ee97dc6110c11af39adc600beceec
--- /dev/null
+++ b/web/yarn.lock
@@ -0,0 +1,2140 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.0.0":
+  version "7.14.5"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
+  integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
+  dependencies:
+    "@babel/highlight" "^7.14.5"
+
+"@babel/helper-validator-identifier@^7.14.5":
+  version "7.14.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
+  integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
+
+"@babel/highlight@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
+  integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.14.5"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
+"@discoveryjs/json-ext@^0.5.0":
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d"
+  integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==
+
+"@popperjs/core@^2.9.2":
+  version "2.9.3"
+  resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.3.tgz#8b68da1ebd7fc603999cf6ebee34a4899a14b88e"
+  integrity sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ==
+
+"@trysound/sax@0.1.1":
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
+  integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==
+
+"@types/bootstrap@5.1.9":
+  version "5.1.9"
+  resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-5.1.9.tgz#55b9bea862667e351e9873ff94fad7cd0be10c5f"
+  integrity sha512-Tembe6lt7819EUzV5LSG9uuwULm4hdEGV9LZ8QBYpWc0J+a+9DdmJEwZ4FMaXGVJWwumTPSkJ8JQF0/KDAmXYg==
+  dependencies:
+    "@popperjs/core" "^2.9.2"
+    "@types/jquery" "*"
+
+"@types/eslint-scope@^3.7.3":
+  version "3.7.3"
+  resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224"
+  integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==
+  dependencies:
+    "@types/eslint" "*"
+    "@types/estree" "*"
+
+"@types/eslint@*":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.0.tgz#7e41f2481d301c68e14f483fe10b017753ce8d5a"
+  integrity sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==
+  dependencies:
+    "@types/estree" "*"
+    "@types/json-schema" "*"
+
+"@types/estree@*":
+  version "0.0.50"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
+  integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==
+
+"@types/estree@^0.0.51":
+  version "0.0.51"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40"
+  integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
+
+"@types/geojson@*":
+  version "7946.0.8"
+  resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca"
+  integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==
+
+"@types/glob@^7.1.1":
+  version "7.1.4"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672"
+  integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==
+  dependencies:
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/jquery@*":
+  version "3.5.6"
+  resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.6.tgz#97ac8e36dccd8ad8ed3f3f3b48933614d9fd8cf0"
+  integrity sha512-SmgCQRzGPId4MZQKDj9Hqc6kSXFNWZFHpELkyK8AQhf8Zr6HKfCzFv9ZC1Fv3FyQttJZOlap3qYb12h61iZAIg==
+  dependencies:
+    "@types/sizzle" "*"
+
+"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
+  version "7.0.9"
+  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
+  integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
+
+"@types/leaflet.markercluster@1.4.6":
+  version "1.4.6"
+  resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.6.tgz#1159460b374ba5e329cb678d0e427f99dca75be5"
+  integrity sha512-MD+bUDzxHznY0zOlSBUAMNQUGB2+xpJPKrR2MNEoBAAKa3QTKJJySBtCqWyGLvYNNO+Cdyc2c64aF2IFwe4fcQ==
+  dependencies:
+    "@types/leaflet" "*"
+
+"@types/leaflet@*":
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.4.tgz#bb9430f69d588ca5829c1ba82657e179454f93a1"
+  integrity sha512-a3qYlMwJ62+WRoiDmYODUD4KywA14jP2XohAkAWtELGuMAD3MohZa/MmIvQDqF52xNI9OYaY8BMsL+9z7yf2HQ==
+  dependencies:
+    "@types/geojson" "*"
+
+"@types/leaflet@1.7.9":
+  version "1.7.9"
+  resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.7.9.tgz#7993d34f14cfa88c45b3d490daba39a3a1be9a2b"
+  integrity sha512-H8vPgD49HKzqM41ArHGZM70g/tfhp8W+JcPxfnF+5H/Xvp+xiP+KQOUNWU8U89fqS1Jj3cpRY/+nbnaHFzwnFA==
+  dependencies:
+    "@types/geojson" "*"
+
+"@types/minimatch@*":
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
+  integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
+
+"@types/node@*":
+  version "16.7.2"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.2.tgz#0465a39b5456b61a04d98bd5545f8b34be340cb7"
+  integrity sha512-TbG4TOx9hng8FKxaVrCisdaxKxqEwJ3zwHoCWXZ0Jw6mnvTInpaB99/2Cy4+XxpXtjNv9/TgfGSvZFyfV/t8Fw==
+
+"@types/parse-json@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
+  integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+
+"@types/sizzle@*":
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef"
+  integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==
+
+"@webassemblyjs/ast@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
+  integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==
+  dependencies:
+    "@webassemblyjs/helper-numbers" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+
+"@webassemblyjs/floating-point-hex-parser@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f"
+  integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==
+
+"@webassemblyjs/helper-api-error@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16"
+  integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==
+
+"@webassemblyjs/helper-buffer@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5"
+  integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==
+
+"@webassemblyjs/helper-numbers@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae"
+  integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==
+  dependencies:
+    "@webassemblyjs/floating-point-hex-parser" "1.11.1"
+    "@webassemblyjs/helper-api-error" "1.11.1"
+    "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1"
+  integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==
+
+"@webassemblyjs/helper-wasm-section@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a"
+  integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-buffer" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/wasm-gen" "1.11.1"
+
+"@webassemblyjs/ieee754@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614"
+  integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==
+  dependencies:
+    "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5"
+  integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==
+  dependencies:
+    "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff"
+  integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==
+
+"@webassemblyjs/wasm-edit@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6"
+  integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-buffer" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/helper-wasm-section" "1.11.1"
+    "@webassemblyjs/wasm-gen" "1.11.1"
+    "@webassemblyjs/wasm-opt" "1.11.1"
+    "@webassemblyjs/wasm-parser" "1.11.1"
+    "@webassemblyjs/wast-printer" "1.11.1"
+
+"@webassemblyjs/wasm-gen@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76"
+  integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/ieee754" "1.11.1"
+    "@webassemblyjs/leb128" "1.11.1"
+    "@webassemblyjs/utf8" "1.11.1"
+
+"@webassemblyjs/wasm-opt@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2"
+  integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-buffer" "1.11.1"
+    "@webassemblyjs/wasm-gen" "1.11.1"
+    "@webassemblyjs/wasm-parser" "1.11.1"
+
+"@webassemblyjs/wasm-parser@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199"
+  integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-api-error" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/ieee754" "1.11.1"
+    "@webassemblyjs/leb128" "1.11.1"
+    "@webassemblyjs/utf8" "1.11.1"
+
+"@webassemblyjs/wast-printer@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0"
+  integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@xtuc/long" "4.2.2"
+
+"@webpack-cli/configtest@^1.1.1":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356"
+  integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==
+
+"@webpack-cli/info@^1.4.1":
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea"
+  integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==
+  dependencies:
+    envinfo "^7.7.3"
+
+"@webpack-cli/serve@^1.6.1":
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe"
+  integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==
+
+"@xtuc/ieee754@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+  integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+  integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+acorn-import-assertions@^1.7.6:
+  version "1.7.6"
+  resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz#580e3ffcae6770eebeec76c3b9723201e9d01f78"
+  integrity sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==
+
+acorn@^8.4.1:
+  version "8.4.1"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c"
+  integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==
+
+ajv-formats@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+  integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
+  dependencies:
+    ajv "^8.0.0"
+
+ajv-keywords@^3.5.2:
+  version "3.5.2"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
+  integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
+
+ajv-keywords@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16"
+  integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==
+  dependencies:
+    fast-deep-equal "^3.1.3"
+
+ajv@^6.12.5:
+  version "6.12.6"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ajv@^8.0.0, ajv@^8.8.0:
+  version "8.10.0"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d"
+  integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    json-schema-traverse "^1.0.0"
+    require-from-string "^2.0.2"
+    uri-js "^4.2.2"
+
+alphanum-sort@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
+  integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
+
+ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+ansi-styles@^4.1.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+  dependencies:
+    color-convert "^2.0.1"
+
+anymatch@~3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
+  integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
+  dependencies:
+    normalize-path "^3.0.0"
+    picomatch "^2.0.4"
+
+array-union@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
+  integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
+  dependencies:
+    array-uniq "^1.0.1"
+
+array-uniq@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+  integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
+
+autoprefixer@10.4.2:
+  version "10.4.2"
+  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b"
+  integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==
+  dependencies:
+    browserslist "^4.19.1"
+    caniuse-lite "^1.0.30001297"
+    fraction.js "^4.1.2"
+    normalize-range "^0.1.2"
+    picocolors "^1.0.0"
+    postcss-value-parser "^4.2.0"
+
+balanced-match@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+boolbase@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
+
+bootstrap@5.1.3:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.3.tgz#ba081b0c130f810fa70900acbc1c6d3c28fa8f34"
+  integrity sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^3.0.1, braces@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
+browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.6:
+  version "4.16.8"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.8.tgz#cb868b0b554f137ba6e33de0ecff2eda403c4fb0"
+  integrity sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==
+  dependencies:
+    caniuse-lite "^1.0.30001251"
+    colorette "^1.3.0"
+    electron-to-chromium "^1.3.811"
+    escalade "^3.1.1"
+    node-releases "^1.1.75"
+
+browserslist@^4.19.1:
+  version "4.20.0"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.0.tgz#35951e3541078c125d36df76056e94738a52ebe9"
+  integrity sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==
+  dependencies:
+    caniuse-lite "^1.0.30001313"
+    electron-to-chromium "^1.4.76"
+    escalade "^3.1.1"
+    node-releases "^2.0.2"
+    picocolors "^1.0.0"
+
+buffer-from@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+  integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
+callsites@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+caniuse-api@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
+  integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
+  dependencies:
+    browserslist "^4.0.0"
+    caniuse-lite "^1.0.0"
+    lodash.memoize "^4.1.2"
+    lodash.uniq "^4.5.0"
+
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001251, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001313:
+  version "1.0.30001314"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001314.tgz#65c7f9fb7e4594fca0a333bec1d8939662377596"
+  integrity sha512-0zaSO+TnCHtHJIbpLroX7nsD+vYuOVjl3uzFbJO1wMVbuveJA0RK2WcQA9ZUIOiO0/ArMiMgHJLxfEZhQiC0kw==
+
+chalk@^2.0.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@^4.1.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+"chokidar@>=3.0.0 <4.0.0":
+  version "3.5.2"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
+  integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
+  dependencies:
+    anymatch "~3.1.2"
+    braces "~3.0.2"
+    glob-parent "~5.1.2"
+    is-binary-path "~2.1.0"
+    is-glob "~4.0.1"
+    normalize-path "~3.0.0"
+    readdirp "~3.6.0"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+chrome-trace-event@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
+  integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
+
+clean-webpack-plugin@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz#72947d4403d452f38ed61a9ff0ada8122aacd729"
+  integrity sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==
+  dependencies:
+    del "^4.1.1"
+
+clone-deep@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
+  integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
+  dependencies:
+    is-plain-object "^2.0.4"
+    kind-of "^6.0.2"
+    shallow-clone "^3.0.0"
+
+color-convert@^1.9.0:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+colord@^2.0.1, colord@^2.6:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/colord/-/colord-2.7.0.tgz#706ea36fe0cd651b585eb142fe64b6480185270e"
+  integrity sha512-pZJBqsHz+pYyw3zpX6ZRXWoCHM1/cvFikY9TV8G3zcejCaKE0lhankoj8iScyrrePA8C7yJ5FStfA9zbcOnw7Q==
+
+colorette@^1.2.2, colorette@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af"
+  integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==
+
+colorette@^2.0.14:
+  version "2.0.16"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da"
+  integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==
+
+commander@^2.20.0:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@^7.0.0, commander@^7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+  integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+cosmiconfig@^7.0.0:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
+  integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
+  dependencies:
+    "@types/parse-json" "^4.0.0"
+    import-fresh "^3.2.1"
+    parse-json "^5.0.0"
+    path-type "^4.0.0"
+    yaml "^1.10.0"
+
+cross-spawn@^7.0.3:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+  integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+  dependencies:
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
+
+css-color-names@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-1.0.1.tgz#6ff7ee81a823ad46e020fa2fd6ab40a887e2ba67"
+  integrity sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA==
+
+css-declaration-sorter@^6.0.3:
+  version "6.1.1"
+  resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.1.tgz#77b32b644ba374bc562c0fc6f4fdaba4dfb0b749"
+  integrity sha512-BZ1aOuif2Sb7tQYY1GeCjG7F++8ggnwUkH5Ictw0mrdpqpEd+zWmcPdstnH2TItlb74FqR0DrVEieon221T/1Q==
+  dependencies:
+    timsort "^0.3.0"
+
+css-loader@6.7.1:
+  version "6.7.1"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e"
+  integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==
+  dependencies:
+    icss-utils "^5.1.0"
+    postcss "^8.4.7"
+    postcss-modules-extract-imports "^3.0.0"
+    postcss-modules-local-by-default "^4.0.0"
+    postcss-modules-scope "^3.0.0"
+    postcss-modules-values "^4.0.0"
+    postcss-value-parser "^4.2.0"
+    semver "^7.3.5"
+
+css-minimizer-webpack-plugin@3.4.1:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f"
+  integrity sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==
+  dependencies:
+    cssnano "^5.0.6"
+    jest-worker "^27.0.2"
+    postcss "^8.3.5"
+    schema-utils "^4.0.0"
+    serialize-javascript "^6.0.0"
+    source-map "^0.6.1"
+
+css-select@^4.1.3:
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067"
+  integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==
+  dependencies:
+    boolbase "^1.0.0"
+    css-what "^5.0.0"
+    domhandler "^4.2.0"
+    domutils "^2.6.0"
+    nth-check "^2.0.0"
+
+css-tree@^1.1.2, css-tree@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
+  integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+  dependencies:
+    mdn-data "2.0.14"
+    source-map "^0.6.1"
+
+css-what@^5.0.0:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad"
+  integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==
+
+cssesc@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+  integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+cssnano-preset-default@^5.1.4:
+  version "5.1.4"
+  resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.4.tgz#359943bf00c5c8e05489f12dd25f3006f2c1cbd2"
+  integrity sha512-sPpQNDQBI3R/QsYxQvfB4mXeEcWuw0wGtKtmS5eg8wudyStYMgKOQT39G07EbW1LB56AOYrinRS9f0ig4Y3MhQ==
+  dependencies:
+    css-declaration-sorter "^6.0.3"
+    cssnano-utils "^2.0.1"
+    postcss-calc "^8.0.0"
+    postcss-colormin "^5.2.0"
+    postcss-convert-values "^5.0.1"
+    postcss-discard-comments "^5.0.1"
+    postcss-discard-duplicates "^5.0.1"
+    postcss-discard-empty "^5.0.1"
+    postcss-discard-overridden "^5.0.1"
+    postcss-merge-longhand "^5.0.2"
+    postcss-merge-rules "^5.0.2"
+    postcss-minify-font-values "^5.0.1"
+    postcss-minify-gradients "^5.0.2"
+    postcss-minify-params "^5.0.1"
+    postcss-minify-selectors "^5.1.0"
+    postcss-normalize-charset "^5.0.1"
+    postcss-normalize-display-values "^5.0.1"
+    postcss-normalize-positions "^5.0.1"
+    postcss-normalize-repeat-style "^5.0.1"
+    postcss-normalize-string "^5.0.1"
+    postcss-normalize-timing-functions "^5.0.1"
+    postcss-normalize-unicode "^5.0.1"
+    postcss-normalize-url "^5.0.2"
+    postcss-normalize-whitespace "^5.0.1"
+    postcss-ordered-values "^5.0.2"
+    postcss-reduce-initial "^5.0.1"
+    postcss-reduce-transforms "^5.0.1"
+    postcss-svgo "^5.0.2"
+    postcss-unique-selectors "^5.0.1"
+
+cssnano-utils@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2"
+  integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ==
+
+cssnano@^5.0.6:
+  version "5.0.8"
+  resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.8.tgz#39ad166256980fcc64faa08c9bb18bb5789ecfa9"
+  integrity sha512-Lda7geZU0Yu+RZi2SGpjYuQz4HI4/1Y+BhdD0jL7NXAQ5larCzVn+PUGuZbDMYz904AXXCOgO5L1teSvgu7aFg==
+  dependencies:
+    cssnano-preset-default "^5.1.4"
+    is-resolvable "^1.1.0"
+    lilconfig "^2.0.3"
+    yaml "^1.10.2"
+
+csso@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
+  integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
+  dependencies:
+    css-tree "^1.1.2"
+
+del@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4"
+  integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==
+  dependencies:
+    "@types/glob" "^7.1.1"
+    globby "^6.1.0"
+    is-path-cwd "^2.0.0"
+    is-path-in-cwd "^2.0.0"
+    p-map "^2.0.0"
+    pify "^4.0.1"
+    rimraf "^2.6.3"
+
+dom-serializer@^1.0.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
+  integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
+  dependencies:
+    domelementtype "^2.0.1"
+    domhandler "^4.2.0"
+    entities "^2.0.0"
+
+domelementtype@^2.0.1, domelementtype@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
+  integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
+
+domhandler@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
+  integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
+  dependencies:
+    domelementtype "^2.2.0"
+
+domutils@^2.6.0:
+  version "2.8.0"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+  integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+  dependencies:
+    dom-serializer "^1.0.1"
+    domelementtype "^2.2.0"
+    domhandler "^4.2.0"
+
+electron-to-chromium@^1.3.811:
+  version "1.3.818"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.818.tgz#32ed024fa8316e5d469c96eecbea7d2463d80085"
+  integrity sha512-c/Z9gIr+jDZAR9q+mn40hEc1NharBT+8ejkarjbCDnBNFviI6hvcC5j2ezkAXru//bTnQp5n6iPi0JA83Tla1Q==
+
+electron-to-chromium@^1.4.76:
+  version "1.4.80"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.80.tgz#299a1ea3e32810934b4e3c2e4d4cb53136fdab3f"
+  integrity sha512-COsbJCGVYCc/aAY4cd94x1Js3q0r406YKGbdL8LXHg0O9dEjuFEFU/vZneRxBxKo/f1lLHi0YyAR7sbFM+i8Bg==
+
+enhanced-resolve@^5.0.0:
+  version "5.8.2"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz#15ddc779345cbb73e97c611cd00c01c1e7bf4d8b"
+  integrity sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==
+  dependencies:
+    graceful-fs "^4.2.4"
+    tapable "^2.2.0"
+
+enhanced-resolve@^5.9.2:
+  version "5.9.2"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9"
+  integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==
+  dependencies:
+    graceful-fs "^4.2.4"
+    tapable "^2.2.0"
+
+entities@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+  integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+envinfo@^7.7.3:
+  version "7.8.1"
+  resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475"
+  integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==
+
+error-ex@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+es-module-lexer@^0.9.0:
+  version "0.9.3"
+  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19"
+  integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
+
+escalade@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+eslint-scope@5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+  integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+  dependencies:
+    esrecurse "^4.3.0"
+    estraverse "^4.1.1"
+
+esrecurse@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+  integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+  dependencies:
+    estraverse "^5.2.0"
+
+estraverse@^4.1.1:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
+  integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
+
+events@^3.2.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+  integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+execa@^5.0.0:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+  integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+  dependencies:
+    cross-spawn "^7.0.3"
+    get-stream "^6.0.0"
+    human-signals "^2.1.0"
+    is-stream "^2.0.0"
+    merge-stream "^2.0.0"
+    npm-run-path "^4.0.1"
+    onetime "^5.1.2"
+    signal-exit "^3.0.3"
+    strip-final-newline "^2.0.0"
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fastest-levenshtein@^1.0.12:
+  version "1.0.12"
+  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
+  integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
+
+fill-range@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+  dependencies:
+    to-regex-range "^5.0.1"
+
+find-up@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+  integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+  dependencies:
+    locate-path "^5.0.0"
+    path-exists "^4.0.0"
+
+fraction.js@^4.1.2:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
+  integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+fsevents@~2.3.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+get-stream@^6.0.0:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+  integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
+glob-parent@~5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+  dependencies:
+    is-glob "^4.0.1"
+
+glob-to-regexp@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+  integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
+glob@^7.0.3, glob@^7.1.3:
+  version "7.1.7"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
+  integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
+  dependencies:
+    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"
+
+globby@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
+  integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
+  dependencies:
+    array-union "^1.0.1"
+    glob "^7.0.3"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+graceful-fs@^4.1.2, graceful-fs@^4.2.4:
+  version "4.2.8"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
+  integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
+
+graceful-fs@^4.2.9:
+  version "4.2.9"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
+  integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+  dependencies:
+    function-bind "^1.1.1"
+
+human-signals@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+  integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
+icss-utils@^5.0.0, icss-utils@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
+  integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
+
+immutable@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
+  integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
+
+import-fresh@^3.2.1:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+  integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+  dependencies:
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+import-local@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6"
+  integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==
+  dependencies:
+    pkg-dir "^4.2.0"
+    resolve-cwd "^3.0.0"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+interpret@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
+  integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
+
+is-absolute-url@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698"
+  integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+is-binary-path@~2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+  dependencies:
+    binary-extensions "^2.0.0"
+
+is-core-module@^2.2.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19"
+  integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==
+  dependencies:
+    has "^1.0.3"
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-glob@^4.0.1, is-glob@~4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+  integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-path-cwd@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
+  integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
+
+is-path-in-cwd@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb"
+  integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==
+  dependencies:
+    is-path-inside "^2.1.0"
+
+is-path-inside@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2"
+  integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==
+  dependencies:
+    path-is-inside "^1.0.2"
+
+is-plain-object@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+  integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+  dependencies:
+    isobject "^3.0.1"
+
+is-resolvable@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
+  integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==
+
+is-stream@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+  integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+  integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+jest-worker@^27.0.2:
+  version "27.0.6"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.6.tgz#a5fdb1e14ad34eb228cfe162d9f729cdbfa28aed"
+  integrity sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==
+  dependencies:
+    "@types/node" "*"
+    merge-stream "^2.0.0"
+    supports-color "^8.0.0"
+
+js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+json-parse-better-errors@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+
+json-parse-even-better-errors@^2.3.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+  integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema-traverse@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+  integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
+kind-of@^6.0.2:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+  integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+klona@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
+  integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
+
+klona@^2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc"
+  integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==
+
+leaflet.markercluster@1.5.3:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz#9cdb52a4eab92671832e1ef9899669e80efc4056"
+  integrity sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==
+
+leaflet@1.7.1:
+  version "1.7.1"
+  resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.7.1.tgz#10d684916edfe1bf41d688a3b97127c0322a2a19"
+  integrity sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==
+
+lilconfig@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd"
+  integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==
+
+lines-and-columns@^1.1.6:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
+  integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
+
+loader-runner@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384"
+  integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==
+
+locate-path@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+  integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+  dependencies:
+    p-locate "^4.1.0"
+
+lodash.memoize@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+  integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
+
+lodash.uniq@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+  integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
+
+lru-cache@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+  integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+  dependencies:
+    yallist "^4.0.0"
+
+mdn-data@2.0.14:
+  version "2.0.14"
+  resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
+  integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
+
+merge-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+  integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+micromatch@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
+  integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
+  dependencies:
+    braces "^3.0.1"
+    picomatch "^2.2.3"
+
+mime-db@1.49.0:
+  version "1.49.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
+  integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
+
+mime-types@^2.1.27:
+  version "2.1.32"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5"
+  integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==
+  dependencies:
+    mime-db "1.49.0"
+
+mimic-fn@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+mini-css-extract-plugin@2.6.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.0.tgz#578aebc7fc14d32c0ad304c2c34f08af44673f5e"
+  integrity sha512-ndG8nxCEnAemsg4FSgS+yNyHKgkTB4nPKqCOgh65j3/30qqC5RaSQQXMm++Y6sb6E1zRSxPkztj9fqxhS1Eo6w==
+  dependencies:
+    schema-utils "^4.0.0"
+
+minimatch@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+nanoid@^3.1.23:
+  version "3.1.25"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
+  integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
+
+nanoid@^3.3.1:
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
+  integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
+
+neo-async@^2.6.2:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+  integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
+node-releases@^1.1.75:
+  version "1.1.75"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe"
+  integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==
+
+node-releases@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01"
+  integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-range@^0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
+  integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
+
+normalize-url@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+  integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+
+npm-run-path@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+  integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+  dependencies:
+    path-key "^3.0.0"
+
+nth-check@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
+  integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
+  dependencies:
+    boolbase "^1.0.0"
+
+object-assign@^4.0.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+  integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+once@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+  dependencies:
+    wrappy "1"
+
+onetime@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+  integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+  dependencies:
+    mimic-fn "^2.1.0"
+
+p-limit@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+  integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+  dependencies:
+    p-try "^2.0.0"
+
+p-limit@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+  dependencies:
+    yocto-queue "^0.1.0"
+
+p-locate@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+  integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+  dependencies:
+    p-limit "^2.2.0"
+
+p-map@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
+  integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
+
+p-try@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
+
+parse-json@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    error-ex "^1.3.1"
+    json-parse-even-better-errors "^2.3.0"
+    lines-and-columns "^1.1.6"
+
+path-exists@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+  integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+  integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-key@^3.0.0, path-key@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-parse@^1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-type@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
+  integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+  integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pify@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+  integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+  integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+pkg-dir@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+  integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
+  dependencies:
+    find-up "^4.0.0"
+
+postcss-calc@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a"
+  integrity sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g==
+  dependencies:
+    postcss-selector-parser "^6.0.2"
+    postcss-value-parser "^4.0.2"
+
+postcss-colormin@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.0.tgz#2b620b88c0ff19683f3349f4cf9e24ebdafb2c88"
+  integrity sha512-+HC6GfWU3upe5/mqmxuqYZ9B2Wl4lcoUUNkoaX59nEWV4EtADCMiBqui111Bu8R8IvaZTmqmxrqOAqjbHIwXPw==
+  dependencies:
+    browserslist "^4.16.6"
+    caniuse-api "^3.0.0"
+    colord "^2.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-convert-values@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232"
+  integrity sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg==
+  dependencies:
+    postcss-value-parser "^4.1.0"
+
+postcss-discard-comments@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe"
+  integrity sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==
+
+postcss-discard-duplicates@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d"
+  integrity sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==
+
+postcss-discard-empty@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8"
+  integrity sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==
+
+postcss-discard-overridden@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6"
+  integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q==
+
+postcss-loader@6.2.1:
+  version "6.2.1"
+  resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef"
+  integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==
+  dependencies:
+    cosmiconfig "^7.0.0"
+    klona "^2.0.5"
+    semver "^7.3.5"
+
+postcss-merge-longhand@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41"
+  integrity sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw==
+  dependencies:
+    css-color-names "^1.0.1"
+    postcss-value-parser "^4.1.0"
+    stylehacks "^5.0.1"
+
+postcss-merge-rules@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz#d6e4d65018badbdb7dcc789c4f39b941305d410a"
+  integrity sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg==
+  dependencies:
+    browserslist "^4.16.6"
+    caniuse-api "^3.0.0"
+    cssnano-utils "^2.0.1"
+    postcss-selector-parser "^6.0.5"
+    vendors "^1.0.3"
+
+postcss-minify-font-values@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf"
+  integrity sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA==
+  dependencies:
+    postcss-value-parser "^4.1.0"
+
+postcss-minify-gradients@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.2.tgz#7c175c108f06a5629925d698b3c4cf7bd3864ee5"
+  integrity sha512-7Do9JP+wqSD6Prittitt2zDLrfzP9pqKs2EcLX7HJYxsxCOwrrcLt4x/ctQTsiOw+/8HYotAoqNkrzItL19SdQ==
+  dependencies:
+    colord "^2.6"
+    cssnano-utils "^2.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-minify-params@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c"
+  integrity sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw==
+  dependencies:
+    alphanum-sort "^1.0.2"
+    browserslist "^4.16.0"
+    cssnano-utils "^2.0.1"
+    postcss-value-parser "^4.1.0"
+    uniqs "^2.0.0"
+
+postcss-minify-selectors@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54"
+  integrity sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og==
+  dependencies:
+    alphanum-sort "^1.0.2"
+    postcss-selector-parser "^6.0.5"
+
+postcss-modules-extract-imports@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
+  integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
+
+postcss-modules-local-by-default@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c"
+  integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==
+  dependencies:
+    icss-utils "^5.0.0"
+    postcss-selector-parser "^6.0.2"
+    postcss-value-parser "^4.1.0"
+
+postcss-modules-scope@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
+  integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==
+  dependencies:
+    postcss-selector-parser "^6.0.4"
+
+postcss-modules-values@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
+  integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
+  dependencies:
+    icss-utils "^5.0.0"
+
+postcss-normalize-charset@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0"
+  integrity sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==
+
+postcss-normalize-display-values@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz#62650b965981a955dffee83363453db82f6ad1fd"
+  integrity sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ==
+  dependencies:
+    cssnano-utils "^2.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-normalize-positions@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz#868f6af1795fdfa86fbbe960dceb47e5f9492fe5"
+  integrity sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg==
+  dependencies:
+    postcss-value-parser "^4.1.0"
+
+postcss-normalize-repeat-style@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz#cbc0de1383b57f5bb61ddd6a84653b5e8665b2b5"
+  integrity sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w==
+  dependencies:
+    cssnano-utils "^2.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-normalize-string@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz#d9eafaa4df78c7a3b973ae346ef0e47c554985b0"
+  integrity sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA==
+  dependencies:
+    postcss-value-parser "^4.1.0"
+
+postcss-normalize-timing-functions@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz#8ee41103b9130429c6cbba736932b75c5e2cb08c"
+  integrity sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q==
+  dependencies:
+    cssnano-utils "^2.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-normalize-unicode@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz#82d672d648a411814aa5bf3ae565379ccd9f5e37"
+  integrity sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA==
+  dependencies:
+    browserslist "^4.16.0"
+    postcss-value-parser "^4.1.0"
+
+postcss-normalize-url@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz#ddcdfb7cede1270740cf3e4dfc6008bd96abc763"
+  integrity sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ==
+  dependencies:
+    is-absolute-url "^3.0.3"
+    normalize-url "^6.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-normalize-whitespace@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a"
+  integrity sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA==
+  dependencies:
+    postcss-value-parser "^4.1.0"
+
+postcss-ordered-values@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044"
+  integrity sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ==
+  dependencies:
+    cssnano-utils "^2.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-reduce-initial@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946"
+  integrity sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw==
+  dependencies:
+    browserslist "^4.16.0"
+    caniuse-api "^3.0.0"
+
+postcss-reduce-transforms@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640"
+  integrity sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA==
+  dependencies:
+    cssnano-utils "^2.0.1"
+    postcss-value-parser "^4.1.0"
+
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5:
+  version "6.0.6"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
+  integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==
+  dependencies:
+    cssesc "^3.0.0"
+    util-deprecate "^1.0.2"
+
+postcss-svgo@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.2.tgz#bc73c4ea4c5a80fbd4b45e29042c34ceffb9257f"
+  integrity sha512-YzQuFLZu3U3aheizD+B1joQ94vzPfE6BNUcSYuceNxlVnKKsOtdo6hL9/zyC168Q8EwfLSgaDSalsUGa9f2C0A==
+  dependencies:
+    postcss-value-parser "^4.1.0"
+    svgo "^2.3.0"
+
+postcss-unique-selectors@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc"
+  integrity sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w==
+  dependencies:
+    alphanum-sort "^1.0.2"
+    postcss-selector-parser "^6.0.5"
+    uniqs "^2.0.0"
+
+postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
+  integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
+
+postcss-value-parser@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+  integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@8.4.8, postcss@^8.4.7:
+  version "8.4.8"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.8.tgz#dad963a76e82c081a0657d3a2f3602ce10c2e032"
+  integrity sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ==
+  dependencies:
+    nanoid "^3.3.1"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
+postcss@^8.3.5:
+  version "8.3.6"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea"
+  integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==
+  dependencies:
+    colorette "^1.2.2"
+    nanoid "^3.1.23"
+    source-map-js "^0.6.2"
+
+prettier@2.5.1:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
+  integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+randombytes@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+  integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+  dependencies:
+    safe-buffer "^5.1.0"
+
+readdirp@~3.6.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+  integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+  dependencies:
+    picomatch "^2.2.1"
+
+rechoir@^0.7.0:
+  version "0.7.1"
+  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686"
+  integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==
+  dependencies:
+    resolve "^1.9.0"
+
+require-from-string@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+  integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
+resolve-cwd@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+  integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+  dependencies:
+    resolve-from "^5.0.0"
+
+resolve-from@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-from@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+  integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve@^1.9.0:
+  version "1.20.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
+  integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
+  dependencies:
+    is-core-module "^2.2.0"
+    path-parse "^1.0.6"
+
+rimraf@^2.6.3:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+  integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+  dependencies:
+    glob "^7.1.3"
+
+safe-buffer@^5.1.0:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+sass-loader@12.6.0:
+  version "12.6.0"
+  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.6.0.tgz#5148362c8e2cdd4b950f3c63ac5d16dbfed37bcb"
+  integrity sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==
+  dependencies:
+    klona "^2.0.4"
+    neo-async "^2.6.2"
+
+sass@1.49.9:
+  version "1.49.9"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.9.tgz#b15a189ecb0ca9e24634bae5d1ebc191809712f9"
+  integrity sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==
+  dependencies:
+    chokidar ">=3.0.0 <4.0.0"
+    immutable "^4.0.0"
+    source-map-js ">=0.6.2 <2.0.0"
+
+schema-utils@^3.0.0, schema-utils@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281"
+  integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
+  dependencies:
+    "@types/json-schema" "^7.0.8"
+    ajv "^6.12.5"
+    ajv-keywords "^3.5.2"
+
+schema-utils@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7"
+  integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==
+  dependencies:
+    "@types/json-schema" "^7.0.9"
+    ajv "^8.8.0"
+    ajv-formats "^2.1.1"
+    ajv-keywords "^5.0.0"
+
+semver@^7.3.4, semver@^7.3.5:
+  version "7.3.5"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
+  integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+  dependencies:
+    lru-cache "^6.0.0"
+
+serialize-javascript@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
+  integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
+  dependencies:
+    randombytes "^2.1.0"
+
+shallow-clone@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
+  integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
+  dependencies:
+    kind-of "^6.0.2"
+
+shebang-command@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+  dependencies:
+    shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+signal-exit@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
+  integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
+
+"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+source-map-js@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
+  integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
+
+source-map-support@~0.5.19:
+  version "0.5.19"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
+  integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
+  dependencies:
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
+
+source-map@^0.6.0, source-map@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+source-map@~0.7.2:
+  version "0.7.3"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
+  integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
+
+stable@^0.1.8:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
+strip-final-newline@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+  integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
+stylehacks@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb"
+  integrity sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==
+  dependencies:
+    browserslist "^4.16.0"
+    postcss-selector-parser "^6.0.4"
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+  dependencies:
+    has-flag "^4.0.0"
+
+supports-color@^8.0.0:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+  integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+  dependencies:
+    has-flag "^4.0.0"
+
+svgo@^2.3.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.5.0.tgz#3c9051b606d85a02fcb59f459b19970d2cc2c9bf"
+  integrity sha512-FSdBOOo271VyF/qZnOn1PgwCdt1v4Dx0Sey+U1jgqm1vqRYjPGdip0RGrFW6ItwtkBB8rHgHk26dlVr0uCs82Q==
+  dependencies:
+    "@trysound/sax" "0.1.1"
+    colorette "^1.3.0"
+    commander "^7.2.0"
+    css-select "^4.1.3"
+    css-tree "^1.1.3"
+    csso "^4.2.0"
+    stable "^0.1.8"
+
+tapable@^2.1.1, tapable@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b"
+  integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==
+
+terser-webpack-plugin@^5.1.3:
+  version "5.1.4"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz#c369cf8a47aa9922bd0d8a94fe3d3da11a7678a1"
+  integrity sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA==
+  dependencies:
+    jest-worker "^27.0.2"
+    p-limit "^3.1.0"
+    schema-utils "^3.0.0"
+    serialize-javascript "^6.0.0"
+    source-map "^0.6.1"
+    terser "^5.7.0"
+
+terser@^5.7.0:
+  version "5.7.2"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.2.tgz#d4d95ed4f8bf735cb933e802f2a1829abf545e3f"
+  integrity sha512-0Omye+RD4X7X69O0eql3lC4Heh/5iLj3ggxR/B5ketZLOtLiOqukUgjw3q4PDnNQbsrkKr3UMypqStQG3XKRvw==
+  dependencies:
+    commander "^2.20.0"
+    source-map "~0.7.2"
+    source-map-support "~0.5.19"
+
+timsort@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
+  integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
+
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
+ts-loader@9.2.7:
+  version "9.2.7"
+  resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.7.tgz#948654099ca96992b62ec47bd9cee5632006e101"
+  integrity sha512-Fxh44mKli9QezgbdCXkEJWxnedQ0ead7DXTH+lfXEPedu+Y9EtMJ2aQ9G3Dj1j7Q612E8931rww8NDZha4Tibg==
+  dependencies:
+    chalk "^4.1.0"
+    enhanced-resolve "^5.0.0"
+    micromatch "^4.0.0"
+    semver "^7.3.4"
+
+typescript@4.6.2:
+  version "4.6.2"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4"
+  integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==
+
+uniqs@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
+  integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI=
+
+uri-js@^4.2.2:
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+  dependencies:
+    punycode "^2.1.0"
+
+util-deprecate@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+vendors@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e"
+  integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==
+
+watchpack@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25"
+  integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==
+  dependencies:
+    glob-to-regexp "^0.4.1"
+    graceful-fs "^4.1.2"
+
+webpack-cli@4.9.2:
+  version "4.9.2"
+  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.2.tgz#77c1adaea020c3f9e2db8aad8ea78d235c83659d"
+  integrity sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==
+  dependencies:
+    "@discoveryjs/json-ext" "^0.5.0"
+    "@webpack-cli/configtest" "^1.1.1"
+    "@webpack-cli/info" "^1.4.1"
+    "@webpack-cli/serve" "^1.6.1"
+    colorette "^2.0.14"
+    commander "^7.0.0"
+    execa "^5.0.0"
+    fastest-levenshtein "^1.0.12"
+    import-local "^3.0.2"
+    interpret "^2.2.0"
+    rechoir "^0.7.0"
+    webpack-merge "^5.7.3"
+
+webpack-merge@^5.7.3:
+  version "5.8.0"
+  resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61"
+  integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==
+  dependencies:
+    clone-deep "^4.0.1"
+    wildcard "^2.0.0"
+
+webpack-sources@^3.2.3:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+  integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack@5.70.0:
+  version "5.70.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.70.0.tgz#3461e6287a72b5e6e2f4872700bc8de0d7500e6d"
+  integrity sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==
+  dependencies:
+    "@types/eslint-scope" "^3.7.3"
+    "@types/estree" "^0.0.51"
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/wasm-edit" "1.11.1"
+    "@webassemblyjs/wasm-parser" "1.11.1"
+    acorn "^8.4.1"
+    acorn-import-assertions "^1.7.6"
+    browserslist "^4.14.5"
+    chrome-trace-event "^1.0.2"
+    enhanced-resolve "^5.9.2"
+    es-module-lexer "^0.9.0"
+    eslint-scope "5.1.1"
+    events "^3.2.0"
+    glob-to-regexp "^0.4.1"
+    graceful-fs "^4.2.9"
+    json-parse-better-errors "^1.0.2"
+    loader-runner "^4.2.0"
+    mime-types "^2.1.27"
+    neo-async "^2.6.2"
+    schema-utils "^3.1.0"
+    tapable "^2.1.1"
+    terser-webpack-plugin "^5.1.3"
+    watchpack "^2.3.1"
+    webpack-sources "^3.2.3"
+
+which@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+  dependencies:
+    isexe "^2.0.0"
+
+wildcard@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
+  integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+yallist@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+  integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yaml@^1.10.0, yaml@^1.10.2:
+  version "1.10.2"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==