diff --git a/.gitignore_recorder b/.gitignore_recorder
index 7d1a7b68fe94a670b1ee7e52632e231478e013f0..2447eff3a26057275ced9afce3380441674df89a 100644
--- a/.gitignore_recorder
+++ b/.gitignore_recorder
@@ -123,9 +123,6 @@ typings/
 # Yarn Integrity file
 .yarn-integrity
 
-# dotenv environment variables file
-.env
-.env.test
 
 # parcel-bundler cache (https://parceljs.org/)
 .cache
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index dc83a81d2b421de89432d5d80756b977f740ce29..a435124f01153c6f99a642a9ea784e84e2431b33 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,24 +1,96 @@
+variables:
+  EXTENSION_PATH: "./deadlock-plugins/deadlock-extension"
+  REGISTRY: "registry.takima.io"
+
 stages:
   - build
+  - publish
 
-before_script:
-  - apk update
-  - apk add nodejs npm
-  - apk add yarn
-  - apk add curl
-  - export TAG=${CI_COMMIT_TAG:-latest}
 
 build:
   stage: build
   services:
     - docker:18.09.6-dind
-  parallel:
-    matrix:
-      - VERSION: [code, kube]
+  variables:
+    VERSION: "desktop"
+
+  before_script:
+    - apk update
+    - apk add nodejs npm
+    - export TAG=${CI_COMMIT_TAG:-latest}
+    - ./setup.sh
   script:
-    - ./build.sh $TAG $VERSION $CI_REGISTRY_IMAGE
-    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.e-biz.fr
+    - ./build.sh $TAG desktop $CI_REGISTRY_IMAGE
+    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $REGISTRY
     - docker push $CI_REGISTRY_IMAGE/$VERSION:$TAG
   only:
     - master
-    - tags
+
+desktop_extension:package:pre-release:
+  stage: build
+  cache:
+    paths:
+      - $EXTENSION_PATH
+    policy: push
+  before_script:
+    - apk update
+    - apk add nodejs npm
+    - rm -f $EXTENSION_PATH/*.vsix
+    - npm install --prefix $EXTENSION_PATH
+  script:
+    - ./build-desktop.sh staging
+  only:
+    - master
+
+
+desktop_extension:publish:pre-release:
+  stage: publish
+  cache:
+    paths:
+      - $EXTENSION_PATH
+    policy: pull
+
+  before_script:
+    - apk update
+    - apk add nodejs npm
+    - npm install --prefix $EXTENSION_PATH
+  script:
+    - cd $EXTENSION_PATH
+    - npm run vsce-publish -- --pre-release -p $VSCODE_EXTENSION_MARKET_PLACE_ACCESS_TOKEN
+  only:
+    - master
+
+
+desktop_extension:package:release:
+  stage: build
+  cache:
+    paths:
+      - $EXTENSION_PATH
+
+    policy: push
+  before_script:
+    - apk update
+    - apk add nodejs npm
+    - rm -f $EXTENSION_PATH/*.vsix
+    - npm install --prefix $EXTENSION_PATH
+  script:
+    - ./build-desktop.sh prod
+  rules:
+    - if: $CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG =~ /^(?:\d+\.){2}(?:\d+)$/
+
+desktop_extension:publish:release:
+  stage: publish
+  cache:
+    paths:
+      - $EXTENSION_PATH
+    policy: pull
+
+  before_script:
+    - apk update
+    - apk add nodejs npm
+    - npm install --prefix $EXTENSION_PATH
+  script:
+    - cd $EXTENSION_PATH
+    - npm run vsce-publish -- -p $VSCODE_EXTENSION_MARKET_PLACE_ACCESS_TOKEN
+  rules:
+    - if: $CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG =~ /^(?:\d+\.){2}(?:\d+)$/
diff --git a/Dockerfile.code b/Dockerfile.code
deleted file mode 100644
index 02e18de9e81209f3c2a0a9a9cba8cc3a247a9849..0000000000000000000000000000000000000000
--- a/Dockerfile.code
+++ /dev/null
@@ -1,28 +0,0 @@
-FROM registry.e-biz.fr/deadlock-public/theia:1.22.1-java
-
-USER root
-
-RUN apt update
-RUN apt upgrade -y
-RUN apt install rsync -y
-RUN apt install vim -y
-
-COPY plugins /home/plugins
-COPY default/.theia/ /home/theia/.theia/
-RUN chown theia /home/theia/.theia -R
-RUN chown theia /home/plugins -R
-
-COPY server.js /home/theia/src-gen/backend/server.js
-
-COPY recorder-out/ deadlock/
-COPY .gitignore_recorder deadlock/.gitignore
-
-COPY setup_trace.py .
-RUN chmod 700 setup_trace.py
-RUN chown theia setup_trace.py
-
-COPY start.sh .
-RUN chmod 504 deadlock/ -R
-RUN chmod 500 start.sh
-
-ENTRYPOINT ["bash", "start.sh"]
diff --git a/Dockerfile.desktop b/Dockerfile.desktop
new file mode 100644
index 0000000000000000000000000000000000000000..84850d36d4c483804b112c25e892e7fb40514c66
--- /dev/null
+++ b/Dockerfile.desktop
@@ -0,0 +1,36 @@
+FROM docker:20.10.16-dind-alpine3.15
+
+RUN apk update
+RUN apk add --update nodejs npm
+RUN apk  --no-cache add vim && apk  --no-cache add nano \
+    && apk  --no-cache add rsync && apk  --no-cache add sudo \
+    && apk  --no-cache add bash && apk  --no-cache add openssh \
+    && apk  --no-cache add git && apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
+
+## User account
+RUN addgroup -S sudo && adduser --disabled-password --gecos '' deadlock && \
+    adduser deadlock sudo && \
+    addgroup -S docker && adduser deadlock docker && \
+    echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
+
+RUN chown root:docker /usr/local/bin/docker
+
+
+COPY setup_trace.py setup_trace.py
+RUN chmod 700 setup_trace.py
+RUN chown deadlock setup_trace.py
+
+COPY recorder-out deadlock/
+COPY .gitignore_recorder deadlock/.gitignore
+
+
+
+COPY start.desktop.sh .
+RUN chmod 504 deadlock/ -R
+RUN chmod 500 start.desktop.sh
+
+RUN mkdir /project && mkdir /tmp/.ssh && mkdir /home/deadlock/mission
+
+RUN chown deadlock:deadlock /home/deadlock
+
+ENTRYPOINT ["bash", "start.desktop.sh"]
\ No newline at end of file
diff --git a/Dockerfile.kube b/Dockerfile.kube
deleted file mode 100644
index 7287ba049b47c0fea230a24b9f832056ab5281f1..0000000000000000000000000000000000000000
--- a/Dockerfile.kube
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM registry.e-biz.fr/deadlock-public/deadlock-theia:1.4
-
-RUN apt-get install -y apt-transport-https
-RUN curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
-RUN echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
-RUN apt-get update
-RUN apt-get install -y kubectl
\ No newline at end of file
diff --git a/README.md b/README.md
index 428481eb4b0d30b949cf41d17331633ffbd087fc..e4ab58074010a8436bc320689ebf9dfd0727d99a 100644
--- a/README.md
+++ b/README.md
@@ -1,42 +1,52 @@
-Deadlock Theia projet basé sur notre propre image de Theia https://git.e-biz.fr/deadlock-public/theia.
-Plusieurs éléments ajoutés à l'image de base :
+Deadlock Desktop est un projet dont l'objectif est de permettre à un étudiant de réaliser des exercices deadlock
+sur son IDE Vscode directement. Pour cela, le répertoire héberge 3 éléments :
 
-1. Deadlock plugins (deadlock-plugins/)
-2. Outil d'enregistrment, qui permet d'enregistrer le code quand un utilisateur exécute du code (deadlock(plugins/recorder))
-3. Gestion du CORS (\*.deadlock.io) dans `server.js`
+- **Une extension Vscode** : L'extension est installée sur l'IDE Vscode de l'étudiant et est responsable de l'ouverture
+  de l'exercice dans un [devcontainer](https://code.visualstudio.com/docs/remote/containers).
 
-Deux images de `deadlock-theia` sont build ici, _code_ et _kube_.
+- **Le recorder** : Une application `node` qui va effectuer des sauvegardes du code source de l'étudiant à chaque fois
+  que celui-ci va modifier un fichier ou saisir certaines commandes dans son terminal.
+
+- **Une image Docker** : L'image contient des programmes basiques et le recorder qui est lancé au démarrage
+  du conteneur.
+
+# Requirements:
+
+1. NodeJS > ^14.X
+2. Vscode ou Vscodium
+3. Docker
 
 ## Setup
 
 Afin d'installer les éléments requis pour le développement, vous pouvez lancer le script `./setup.sh`.
 
-## Construire les plugins :
+## L'image Docker desktop
 
-`./build-plugins.sh`
+Il s'agit d'une image qui sera utilisé par tous les créateurs d'exercices comme base.  
+Le créateur d'exercice peut ensuite ajouter l'exercice et les dépendances qu'il souhaite pour créer l'image de son exercice.
 
-Tous les plugins qui se trouvent dans `deadlock-public` vont être construit en `.vsix` puis placés
-dans `plugins/` (ex: deadlock-plugins/deadlock-extension).  
-Il est aussi possible d'ajouter directement des plugins `.vsix` en ajoutant le fichier dans `plugins/`
+L'image est décrite dans le fichier `Dockerfile.desktop`.
 
 ## Recorder :
 
 Le recorder permet de sauvegarder régulièrement le code de l'utilisateur.
-Pour se faire il écoute les commandes exécutées par l'utilisateur et si une contient `java|npm|yarn`
-alors un snapshot du code est réalisé.
+Pour se faire, il écoute les commandes exécutées par l'utilisateur. Si l'une d'entre elles contient `java`, `npm` ou `yarn`
+alors un snapshot du code est réalisé. Il va également faire un snapshot du code lorsque l'étudiant modifiera les fichiers de l'exercice.
 
 ### Build
 
 `./build-recorder.sh`
 
-## Construire l'image Deadlock Theia avec le recorder et les plugins
+## Construire les plugins Vscode :
 
-`./build.sh $TAG (code|kube)`
+`./build-plugins.sh`
 
-# Requirements:
+Tous les plugins qui se trouvent dans `deadlock-public` vont être construit en `.vsix` puis placés
+dans `plugins/` (ex: deadlock-plugins/deadlock-extension).  
+Il est aussi possible d'ajouter directement des plugins `.vsix` en ajoutant le fichier dans `plugins/`
 
-1. NodeJS > ^14.X
-2. Vscode ou Vscodium
-3. Docker
+Plus d'informations sur l'extension `deadlock-coding` dans ce [README](deadlock-plugins/deadlock-extension/dev/README.md).
+
+## Construire l'image Deadlock Desktop avec le recorder
 
-Ce projet contient le minimum pour construire une image Docker Theia avec Blueprint (https://theia-ide.org/docs/composing_applications/)
+`./build.sh $TAG desktop`
diff --git a/build-desktop.sh b/build-desktop.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d7b91cafc058e4ed609036d9e3ce40c0acd16345
--- /dev/null
+++ b/build-desktop.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+set -e
+
+cd ./deadlock-plugins/deadlock-extension/
+
+./install.sh
+./build.sh $@
diff --git a/build-recorder.sh b/build-recorder.sh
index cd2cf4cebc367b36e3acc645f4a57ae263f0e401..2ae07c7d14d3e357c4015d7a82f22f49ad4deb1a 100755
--- a/build-recorder.sh
+++ b/build-recorder.sh
@@ -6,13 +6,10 @@ OUTPUT_DIR='recorder-out'
 
 cd ./deadlock-plugins/deadlock-extension/
 
-npm install
 npm run build-recorder
-npm run build-preStop
 
 cd -
 mkdir -p $OUTPUT_DIR
 cp -r ./deadlock-plugins/deadlock-extension/out/recorder.js $OUTPUT_DIR
-cp -r ./deadlock-plugins/deadlock-extension/out/preStop.js $OUTPUT_DIR
 
 
diff --git a/build.sh b/build.sh
index 6d9e150bfdee0cc6aec9f8c2571cb891d3b5f3c3..960fcd0cb79449d16bd6620e5656abe1a148322a 100755
--- a/build.sh
+++ b/build.sh
@@ -10,10 +10,6 @@ DOCKERFILE="Dockerfile.$VERSION"
 
 echo "Building Dockerfile.$VERSION"
 
-echo '====================================================='
-echo '================= BUILDING PLUGINS =================='
-echo '====================================================='
-./build-plugins.sh
 echo '====================================================='
 echo '================= BUILDING RECORDER ================='
 echo '====================================================='
diff --git a/deadlock-plugins/deadlock-extension/.eslintrc.js b/deadlock-plugins/deadlock-extension/.eslintrc.js
index 2cac4952287f4b6d28a6b22b9a39044d31270618..0de9a9a3633c15296403ab5ab76a2ff7852ea031 100644
--- a/deadlock-plugins/deadlock-extension/.eslintrc.js
+++ b/deadlock-plugins/deadlock-extension/.eslintrc.js
@@ -7,10 +7,11 @@ module.exports = {
   extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
   rules: {
     semi: [2, 'always'],
-    quotes: [2, 'single' | 'backtick', 'avoid-escape'],
-    '@typescript-eslint/no-unused-vars': 0,
+    '@typescript-eslint/no-unused-vars': 'error',
     '@typescript-eslint/no-explicit-any': 0,
     '@typescript-eslint/explicit-module-boundary-types': 0,
     '@typescript-eslint/no-non-null-assertion': 0,
+    '@typescript-eslint/no-var-requires': 0,
+    '@typescript-eslint/no-this-alias': 0,
   },
 };
diff --git a/deadlock-plugins/deadlock-extension/.vscode/extensions.json b/deadlock-plugins/deadlock-extension/.vscode/extensions.json
index 326dae3cd5b9cae9464cbdc6390d11927043f728..57dbdae42d37d5323806c24cefef6387b5770610 100644
--- a/deadlock-plugins/deadlock-extension/.vscode/extensions.json
+++ b/deadlock-plugins/deadlock-extension/.vscode/extensions.json
@@ -1,7 +1,5 @@
 {
-  // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
-  // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
-
-  // List of extensions which should be recommended for users of this workspace.
-  "recommendations": ["dbaeumer.vscode-eslint"]
+  // See http://go.microsoft.com/fwlink/?LinkId=827846
+  // for the documentation about the extensions.json format
+  "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"]
 }
diff --git a/deadlock-plugins/deadlock-extension/.vscode/launch.json b/deadlock-plugins/deadlock-extension/.vscode/launch.json
index 4c4a9c78b100a81bc070816bab70bbcf326ee2c1..cbc9e78604f69f668a120818cce55200eaaaf889 100644
--- a/deadlock-plugins/deadlock-extension/.vscode/launch.json
+++ b/deadlock-plugins/deadlock-extension/.vscode/launch.json
@@ -9,10 +9,20 @@
       "name": "Run Extension",
       "type": "extensionHost",
       "request": "launch",
-      "runtimeExecutable": "${execPath}",
-      "args": ["--extensionDevelopmentPath=${workspaceRoot}"],
-      "outFiles": ["${workspaceFolder}/out/**/*.js"],
-      "preLaunchTask": "npm: watch"
+      "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
+      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
+      "preLaunchTask": "${defaultBuildTask}"
+    },
+    {
+      "name": "Extension Tests",
+      "type": "extensionHost",
+      "request": "launch",
+      "args": [
+        "--extensionDevelopmentPath=${workspaceFolder}",
+        "--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
+      ],
+      "outFiles": ["${workspaceFolder}/out/**/*.js", "${workspaceFolder}/dist/**/*.js"],
+      "preLaunchTask": "tasks: watch-tests"
     }
   ]
 }
diff --git a/deadlock-plugins/deadlock-extension/.vscode/settings.json b/deadlock-plugins/deadlock-extension/.vscode/settings.json
index 194c9b6b6c9840561b2552671bdaa26be65366ba..64ee929665322e5cdd94fb5b7d2ae18f79a27d45 100644
--- a/deadlock-plugins/deadlock-extension/.vscode/settings.json
+++ b/deadlock-plugins/deadlock-extension/.vscode/settings.json
@@ -1,3 +1,13 @@
+// Place your settings in this file to overwrite default and user settings.
 {
-  "editor.insertSpaces": false
+  "files.exclude": {
+    "out": false, // set this to true to hide the "out" folder with the compiled JS files
+    "dist": false // set this to true to hide the "dist" folder with the compiled JS files
+  },
+  "search.exclude": {
+    "out": true, // set this to false to include "out" folder in search results
+    "dist": true // set this to false to include "dist" folder in search results
+  },
+  // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
+  "typescript.tsc.autoDetect": "off"
 }
diff --git a/deadlock-plugins/deadlock-extension/.vscode/tasks.json b/deadlock-plugins/deadlock-extension/.vscode/tasks.json
index 078ff7e01ef583efd188933e6f5af582ec9d81bc..bb452adff76d8709fcb5cec4e14bf672f4e2fcb5 100644
--- a/deadlock-plugins/deadlock-extension/.vscode/tasks.json
+++ b/deadlock-plugins/deadlock-extension/.vscode/tasks.json
@@ -6,15 +6,32 @@
     {
       "type": "npm",
       "script": "watch",
-      "problemMatcher": "$tsc-watch",
+      "problemMatcher": ["$ts-webpack-watch", "$tslint-webpack-watch"],
       "isBackground": true,
       "presentation": {
-        "reveal": "never"
+        "reveal": "never",
+        "group": "watchers"
       },
       "group": {
         "kind": "build",
         "isDefault": true
       }
+    },
+    {
+      "type": "npm",
+      "script": "watch-tests",
+      "problemMatcher": "$tsc-watch",
+      "isBackground": true,
+      "presentation": {
+        "reveal": "never",
+        "group": "watchers"
+      },
+      "group": "build"
+    },
+    {
+      "label": "tasks: watch-tests",
+      "dependsOn": ["npm: watch", "npm: watch-tests"],
+      "problemMatcher": []
     }
   ]
 }
diff --git a/deadlock-plugins/deadlock-extension/.vscodeignore b/deadlock-plugins/deadlock-extension/.vscodeignore
index d626c52f3c583b1db5e9a70958ac2f34ac37a757..62bf20897c27705b453c85d440e97fb4f0d9bc2a 100644
--- a/deadlock-plugins/deadlock-extension/.vscodeignore
+++ b/deadlock-plugins/deadlock-extension/.vscodeignore
@@ -3,4 +3,5 @@ out/
 !out/main.js
 src/
 dev/
-tsconfig.json
\ No newline at end of file
+tsconfig.json
+node_modules
\ No newline at end of file
diff --git a/deadlock-plugins/deadlock-extension/CHANGELOG.md b/deadlock-plugins/deadlock-extension/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..847017bb2c4193e0c83b3b4f075223c0eea50d9c
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/CHANGELOG.md
@@ -0,0 +1,20 @@
+### Changelog
+
+All notable changes to this project will be documented in this file. Dates are displayed in UTC.
+
+Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
+
+#### [0.1.7](https://gitlab.takima.io/deadlock-public/deadlock-desktop/compare/0.1.6...0.1.7)
+
+#### 0.1.6
+
+> 23 May 2022
+
+- feat: publish_extension_on_marketplace_with_ci [`#5`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/merge_requests/5)
+- fix(view): open `Help` panel by default + fix split screen on views opening after several restarts [`#2`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/merge_requests/2)
+- Feat theia professor [`#4`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/merge_requests/4)
+- Pull on start [`#3`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/merge_requests/3)
+- feat: git pull on startup, refactor user-challenge config [`#2`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/merge_requests/2)
+- feat: use new theia build [`43dee03`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/commit/43dee036539001951de56197cf96bc36a46945b7)
+- chores: clean theia resources [`8a8ab05`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/commit/8a8ab05c2a6b723d587dc455fcbe2ae03d608de9)
+- refactor: apply some recommendation [`cc647f5`](https://gitlab.takima.io/deadlock-public/deadlock-desktop/commit/cc647f51cfa9325db11c0450cf8f37ba681c83ca)
diff --git a/deadlock-plugins/deadlock-extension/README.md b/deadlock-plugins/deadlock-extension/README.md
index c24101e2f3ea48b3dbe46de58278e86a648bc763..f5847f3f171a675bbcd426c96f244369f98ca1c9 100644
--- a/deadlock-plugins/deadlock-extension/README.md
+++ b/deadlock-plugins/deadlock-extension/README.md
@@ -1,15 +1,3 @@
-# Deadlock Coding
+## Deadlock Coding extension
 
-Vscode extension to show a panel with :
-
-- adresses availables for the current challenge pulled from `/home/config/user-challenge.json`
-- challenge instruction pulled from the `README.md`
-
-## Quick start
-
-- Run `setup-dev-env.sh` to mock challenge configuration
-- Run `install.sh`
-- Run `build.sh`
-- Press `F5` (or use `Run and Debug` tab).
-
-If something goes wrong, you may need to kill watch Task terminal between restarts.
+This extension was created to allow you to do some of the [Deadlock](https://www.deadlock.io) platform exercises directly on your Visual Studio Code IDE
diff --git a/deadlock-plugins/deadlock-extension/build.sh b/deadlock-plugins/deadlock-extension/build.sh
index 77a6867456b2d485d48814efe422a3c5856ea6e5..5cb1d85ec85fda4fc0c2522dba7b6a15fb99faf6 100755
--- a/deadlock-plugins/deadlock-extension/build.sh
+++ b/deadlock-plugins/deadlock-extension/build.sh
@@ -2,5 +2,16 @@
 
 set -e
 
+CONFIG_FILE=$1
+
+if ! [ -z "$CONFIG_FILE" ]
+  then
+    echo $CONFIG_FILE
+    mv -f src/config.$CONFIG_FILE.ts src/config.ts
+    # Remove all other configs
+    rm src/config.*.ts
+fi
+
+
 npm run build-extension
-npm run vsce
+npm run vsce-package
diff --git a/deadlock-plugins/deadlock-extension/dev/README.md b/deadlock-plugins/deadlock-extension/dev/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b2fb4782cd70d06ce2ca9fe91c679f9dc6ab2e7c
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/dev/README.md
@@ -0,0 +1,80 @@
+# Deadlock Coding
+
+Extension VSCode permettant de :
+
+- récupérer la mission en cours à partir du `/home/config/user-challenge.json`
+- afficher les consignes de la mission depuis un `README.md`.
+
+## Quick start
+
+- Ouvrir le dossier `deadlock-extension` dans Vscode
+- Lancer le script `setup-dev-env.sh` pour simuler la configuration d'une mission
+- Lancer le script `install.sh`
+- Dans l'éditeur, appuyer sur `F5` (ou utiliser l'onglet `Run and Debug`).
+
+## Gitlab CI pour publier l'extension
+
+Le pipeline a besoin d'un token provenant de la marketplace pour y publier l'extension.
+
+- La méthode pour obtenir le token est décrite [ici](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token)
+- Le token doit être inséré en tant que valeur de la variable `VSCODE_EXTENSION_MARKET_PLACE_ACCESS_TOKEN`
+
+**Le token a une durée de vie maximale de 1 an**
+
+## Gestion de la production et de la pré-production
+
+Pour le moment, la marketplace de Vscode ne supporte pas totalement le `semver`([spécialement les suffixes](https://github.com/microsoft/vsmarketplace/issues/50#issuecomment-990764201)). Il n'est pas possible de créer une version `0.0.1-alpha` de l'extension par example.
+
+### Construire une version pré-release
+
+1. Monter la version de l'extension avec `npm version`. Vous pouvez voir comment utiliser la commande [ici](https://docs.npmjs.com/cli/v8/commands/npm-version).
+
+2. Lorsque le travail est poussé sur la branche `master`, une version de l'extension est poussé en `pre-release` sur la marketplace.
+
+### Constuire une version release
+
+1. Monter la version de l'extension avec `npm version`. Vous pouvez voir comment utiliser la commande [ici](https://docs.npmjs.com/cli/v8/commands/npm-version).
+
+2. Pousser le code source et le tag :
+
+```shell
+git tag [X.Y.Z]
+git push origin [taBranch] --tags
+```
+
+### Publier l'extention à la main
+
+Les commandes nécessaires sont prédéfinies dans le package.json :
+
+```shell
+npm run vsce-package
+npm run vsce-publish -- [--pre-release] -p [token]
+```
+
+La méthode pour obtenir le token est décrite [ici](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token)
+
+## Le cas d'usage à essayer
+
+Le cas d'usage à essayer pour valider une US Deadlock Desktop correspond à un scénario utilisateur. Ce scénario doit être mis à jour à chaque mise à jour.
+
+Configuration de base :
+
+- OS: Ubuntu 20.04.4 LTS
+- Navigateur: Mozilla Firefox (v99.0+), Google Chrome (v101.0+)
+- Docker version 20.10.14, build a224086
+- Visual Studio Code (v1.66.2+)
+
+Steps:
+
+1. Aller sur https://www.dev.deadlock.io/. La page d'authentification doit apparaitre.
+2. Se connecter via Google. Être redirigé vers la page d'accueil.
+3. Sélectionner et lancer une mission du type `desktop`. Les instructions de la mission doivent apparaître sur la page.
+4. Tous les liens sur la page de la mission doivent fonctionner : installation de dépendances, la page de l'extension sur la marketplace, et le lien xdg-open permettant d'ouvrir Vscode.
+5. Lorsque VS Code est ouvert, une fenêtre doit apparaitre et suggérer l'installation de l'extension. Accepter l'installation. L'installation doit fonctionner et une notification de bienvenue doit apparaître.
+6. Désinstaller l'extension, relancer l'IDE, et chercher `deadlock` dans la barre de recherche de la `marketplace`. L'extension doit apparaitre dans les 3 premiers résultats. Reinstaller l'extension.
+7. Re-cliquer sur le lien de l'exercice dans le navigateur. La fenêtre demandant de choisir un dossier pour les exercices doit s'ouvrir.
+8. Sélectionner un dossier ne nécessitant pas de droits d'accès. Une page doit s'ouvrir dans le navigateur par défault pour permettre à l'utilisateur de s'authentifier.
+9. S'authentifier avec Google et retourner dans VSCode. Une notification de connexion doit s'afficher.
+10. Ouvrir la page de l'extension, elle doit indiquer que les étapes précédentes (choix du dossier et authentification) ont été validées.
+11. Une fois authentifié, VSCode doit se réouvrir automatiquement dans le `devcontainer`. L'arborescence de fichiers doit être montée dans le dossier des exercices.
+12. Ouvrir le terminal de VSCode. L'utilisateur en cours doit être `deadlock` et les bibliothèques et exécutables nécessaires à la mission doivent être présents (ex: docker, java, node, ...).
diff --git a/deadlock-plugins/deadlock-extension/dev/config/user-challenge.json b/deadlock-plugins/deadlock-extension/dev/ressources/config/user-challenge.json
similarity index 100%
rename from deadlock-plugins/deadlock-extension/dev/config/user-challenge.json
rename to deadlock-plugins/deadlock-extension/dev/ressources/config/user-challenge.json
diff --git a/deadlock-plugins/deadlock-extension/dev/docs/briefing.md b/deadlock-plugins/deadlock-extension/dev/ressources/docs/briefing.md
similarity index 100%
rename from deadlock-plugins/deadlock-extension/dev/docs/briefing.md
rename to deadlock-plugins/deadlock-extension/dev/ressources/docs/briefing.md
diff --git a/deadlock-plugins/deadlock-extension/dev/docs/toast.jpg b/deadlock-plugins/deadlock-extension/dev/ressources/docs/toast.jpg
similarity index 100%
rename from deadlock-plugins/deadlock-extension/dev/docs/toast.jpg
rename to deadlock-plugins/deadlock-extension/dev/ressources/docs/toast.jpg
diff --git a/deadlock-plugins/deadlock-extension/media/logo.png b/deadlock-plugins/deadlock-extension/media/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..a53213f88159e56e029222335fa7876c9c2ee9bd
Binary files /dev/null and b/deadlock-plugins/deadlock-extension/media/logo.png differ
diff --git a/deadlock-plugins/deadlock-extension/package-lock.json b/deadlock-plugins/deadlock-extension/package-lock.json
index b295b7667c31cb60e1d9f701b2cefc4ce3da03cb..d74a34235031d3f9b12d8b19849b57b567b77420 100644
--- a/deadlock-plugins/deadlock-extension/package-lock.json
+++ b/deadlock-plugins/deadlock-extension/package-lock.json
@@ -1,43 +1,52 @@
 {
   "name": "deadlock-coding",
-  "version": "0.0.2",
+  "version": "0.1.7",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "deadlock-coding",
-      "version": "0.0.2",
+      "version": "0.1.7",
       "dependencies": {
         "@vscode/webview-ui-toolkit": "^1.0.0",
         "async": "^3.2.2",
+        "axios": "^0.27.2",
         "crypto-js": "^4.1.1",
         "date-fns": "^2.27.0",
         "inversify": "^6.0.1",
+        "is-docker": "^3.0.0",
         "marked": "^4.0.6",
         "node-fetch": "^3.2.3",
         "reflect-metadata": "^0.1.13",
-        "simple-git": "^2.48.0"
+        "simple-git": "^3.7.0"
       },
       "devDependencies": {
         "@types/crypto-js": "^4.1.1",
+        "@types/glob": "^7.2.0",
         "@types/marked": "^4.0.1",
-        "@types/node": "^12.20.47",
+        "@types/mocha": "^9.1.0",
+        "@types/node": "14.x",
         "@types/node-fetch": "^2.6.1",
-        "@types/vscode": "^1.51.0",
+        "@types/vscode": "^1.66.0",
         "@typescript-eslint/eslint-plugin": "^3.10.1",
         "@typescript-eslint/parser": "^3.10.1",
+        "@vscode/test-electron": "^2.1.3",
+        "auto-changelog": "^2.4.0",
         "esbuild": "^0.14.2",
         "eslint": "^7.32.0",
+        "glob": "^7.2.0",
+        "mocha": "^9.2.2",
         "prettier": "2.6.2",
         "terser-webpack-plugin": "^5.2.5",
+        "ts-loader": "^9.2.8",
         "ts-node": "^9.1.1",
         "typescript": "^3.9.10",
-        "vsce": "^2.5.1",
-        "webpack": "^5.65.0",
-        "webpack-cli": "^4.9.1"
+        "vsce": "^2.7.0",
+        "webpack": "^5.70.0",
+        "webpack-cli": "^4.9.2"
       },
       "engines": {
-        "vscode": "^1.63.0"
+        "vscode": "^1.66.0"
       }
     },
     "node_modules/@babel/code-frame": {
@@ -193,6 +202,15 @@
         "exenv-es6": "^1.1.1"
       }
     },
+    "node_modules/@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/@types/crypto-js": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz",
@@ -200,9 +218,9 @@
       "dev": true
     },
     "node_modules/@types/eslint": {
-      "version": "8.2.1",
-      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz",
-      "integrity": "sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==",
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz",
+      "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==",
       "dev": true,
       "dependencies": {
         "@types/estree": "*",
@@ -210,9 +228,9 @@
       }
     },
     "node_modules/@types/eslint-scope": {
-      "version": "3.7.1",
-      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz",
-      "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==",
+      "version": "3.7.3",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz",
+      "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==",
       "dev": true,
       "dependencies": {
         "@types/eslint": "*",
@@ -226,11 +244,21 @@
       "dev": true
     },
     "node_modules/@types/estree": {
-      "version": "0.0.50",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
-      "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
+      "version": "0.0.51",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
+      "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
       "dev": true
     },
+    "node_modules/@types/glob": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
+      "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
+      "dev": true,
+      "dependencies": {
+        "@types/minimatch": "*",
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/json-schema": {
       "version": "7.0.9",
       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
@@ -243,10 +271,22 @@
       "integrity": "sha512-ZigEmCWdNUU7IjZEuQ/iaimYdDHWHfTe3kg8ORfKjyGYd9RWumPoOJRQXB0bO+XLkNwzCthW3wUIQtANaEZ1ag==",
       "dev": true
     },
+    "node_modules/@types/minimatch": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
+      "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
+      "dev": true
+    },
+    "node_modules/@types/mocha": {
+      "version": "9.1.1",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz",
+      "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==",
+      "dev": true
+    },
     "node_modules/@types/node": {
-      "version": "12.20.47",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.47.tgz",
-      "integrity": "sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==",
+      "version": "14.18.18",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz",
+      "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==",
       "dev": true
     },
     "node_modules/@types/node-fetch": {
@@ -260,9 +300,9 @@
       }
     },
     "node_modules/@types/vscode": {
-      "version": "1.62.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.62.0.tgz",
-      "integrity": "sha512-iGlQJ1w5e3qPUryroO6v4lxg3ql1ztdTCwQW3xEwFawdyPLoeUSv48SYfMwc7kQA7h6ThUqflZIjgKAykeF9oA==",
+      "version": "1.67.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.67.0.tgz",
+      "integrity": "sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==",
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
@@ -403,6 +443,27 @@
         "url": "https://opencollective.com/typescript-eslint"
       }
     },
+    "node_modules/@ungap/promise-all-settled": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+      "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+      "dev": true
+    },
+    "node_modules/@vscode/test-electron": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.3.tgz",
+      "integrity": "sha512-ps/yJ/9ToUZtR1dHfWi1mDXtep1VoyyrmGKC3UnIbScToRQvbUjyy1VMqnMEW3EpMmC3g7+pyThIPtPyCLHyow==",
+      "dev": true,
+      "dependencies": {
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "rimraf": "^3.0.2",
+        "unzipper": "^0.10.11"
+      },
+      "engines": {
+        "node": ">=8.9.3"
+      }
+    },
     "node_modules/@vscode/webview-ui-toolkit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.0.0.tgz",
@@ -563,9 +624,9 @@
       }
     },
     "node_modules/@webpack-cli/configtest": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz",
-      "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz",
+      "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==",
       "dev": true,
       "peerDependencies": {
         "webpack": "4.x.x || 5.x.x",
@@ -573,9 +634,9 @@
       }
     },
     "node_modules/@webpack-cli/info": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz",
-      "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==",
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz",
+      "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==",
       "dev": true,
       "dependencies": {
         "envinfo": "^7.7.3"
@@ -585,9 +646,9 @@
       }
     },
     "node_modules/@webpack-cli/serve": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz",
-      "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==",
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz",
+      "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==",
       "dev": true,
       "peerDependencies": {
         "webpack-cli": "4.x.x"
@@ -640,6 +701,18 @@
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
+    "node_modules/agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -695,6 +768,19 @@
         "node": ">=4"
       }
     },
+    "node_modules/anymatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "dev": true,
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/aproba": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -743,8 +829,77 @@
     "node_modules/asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
-      "dev": true
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+    },
+    "node_modules/auto-changelog": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.4.0.tgz",
+      "integrity": "sha512-vh17hko1c0ItsEcw6m7qPRf3m45u+XK5QyCrrBFViElZ8jnKrPC1roSznrd1fIB/0vR/zawdECCRJtTuqIXaJw==",
+      "dev": true,
+      "dependencies": {
+        "commander": "^7.2.0",
+        "handlebars": "^4.7.7",
+        "node-fetch": "^2.6.1",
+        "parse-github-url": "^1.0.2",
+        "semver": "^7.3.5"
+      },
+      "bin": {
+        "auto-changelog": "src/index.js"
+      },
+      "engines": {
+        "node": ">=8.3"
+      }
+    },
+    "node_modules/auto-changelog/node_modules/commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/auto-changelog/node_modules/node-fetch": {
+      "version": "2.6.7",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+      "dev": true,
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "dependencies": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/axios/node_modules/form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
     },
     "node_modules/azure-devops-node-api": {
       "version": "11.1.0",
@@ -782,6 +937,37 @@
         }
       ]
     },
+    "node_modules/big-integer": {
+      "version": "1.6.51",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
+      "dev": true,
+      "dependencies": {
+        "buffers": "~0.1.1",
+        "chainsaw": "~0.1.0"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/bl": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -807,6 +993,12 @@
         "node": ">= 6"
       }
     },
+    "node_modules/bluebird": {
+      "version": "3.4.7",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+      "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
+      "dev": true
+    },
     "node_modules/boolbase": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -823,6 +1015,24 @@
         "concat-map": "0.0.1"
       }
     },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "dev": true
+    },
     "node_modules/browserslist": {
       "version": "4.18.1",
       "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz",
@@ -885,6 +1095,24 @@
       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
       "dev": true
     },
+    "node_modules/buffer-indexof-polyfill": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
+      "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.2.0"
+      }
+    },
     "node_modules/call-bind": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -907,6 +1135,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/caniuse-lite": {
       "version": "1.0.30001285",
       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz",
@@ -917,6 +1157,18 @@
         "url": "https://opencollective.com/browserslist"
       }
     },
+    "node_modules/chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
+      "dev": true,
+      "dependencies": {
+        "traverse": ">=0.3.0 <0.4"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -1030,6 +1282,33 @@
       "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
       "dev": true
     },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "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"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
     "node_modules/chownr": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
@@ -1045,6 +1324,17 @@
         "node": ">=6.0"
       }
     },
+    "node_modules/cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
     "node_modules/clone-deep": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -1093,7 +1383,6 @@
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
       "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-      "dev": true,
       "dependencies": {
         "delayed-stream": "~1.0.0"
       },
@@ -1214,6 +1503,18 @@
         }
       }
     },
+    "node_modules/decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/decompress-response": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
@@ -1245,7 +1546,6 @@
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
-      "dev": true,
       "engines": {
         "node": ">=0.4.0"
       }
@@ -1344,6 +1644,15 @@
         "url": "https://github.com/fb55/domutils?sponsor=1"
       }
     },
+    "node_modules/duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": "^2.0.2"
+      }
+    },
     "node_modules/electron-to-chromium": {
       "version": "1.4.11",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.11.tgz",
@@ -1366,9 +1675,9 @@
       }
     },
     "node_modules/enhanced-resolve": {
-      "version": "5.8.3",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz",
-      "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==",
+      "version": "5.9.3",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz",
+      "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==",
       "dev": true,
       "dependencies": {
         "graceful-fs": "^4.2.4",
@@ -1795,6 +2104,18 @@
         "node": "^10.12.0 || >=12.0.0"
       }
     },
+    "node_modules/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,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/find-up": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -1808,6 +2129,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true,
+      "bin": {
+        "flat": "cli.js"
+      }
+    },
     "node_modules/flat-cache": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@@ -1827,6 +2157,25 @@
       "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
       "dev": true
     },
+    "node_modules/follow-redirects": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz",
+      "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/form-data": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
@@ -1864,6 +2213,47 @@
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
       "dev": true
     },
+    "node_modules/fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/fstream": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "inherits": "~2.0.0",
+        "mkdirp": ">=0.5 0",
+        "rimraf": "2"
+      },
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/fstream/node_modules/rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      }
+    },
     "node_modules/function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -1939,6 +2329,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
     "node_modules/get-intrinsic": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
@@ -2025,11 +2424,41 @@
       }
     },
     "node_modules/graceful-fs": {
-      "version": "4.2.8",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
-      "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==",
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
       "dev": true
     },
+    "node_modules/growl": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.x"
+      }
+    },
+    "node_modules/handlebars": {
+      "version": "4.7.7",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
+      "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.5",
+        "neo-async": "^2.6.0",
+        "source-map": "^0.6.1",
+        "wordwrap": "^1.0.0"
+      },
+      "bin": {
+        "handlebars": "bin/handlebars"
+      },
+      "engines": {
+        "node": ">=0.4.7"
+      },
+      "optionalDependencies": {
+        "uglify-js": "^3.1.4"
+      }
+    },
     "node_modules/has": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -2069,6 +2498,15 @@
       "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
       "dev": true
     },
+    "node_modules/he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true,
+      "bin": {
+        "he": "bin/he"
+      }
+    },
     "node_modules/hosted-git-info": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz",
@@ -2100,6 +2538,33 @@
         "entities": "^2.0.0"
       }
     },
+    "node_modules/http-proxy-agent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "dev": true,
+      "dependencies": {
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/human-signals": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -2215,6 +2680,18 @@
       "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz",
       "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ=="
     },
+    "node_modules/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,
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/is-core-module": {
       "version": "2.8.0",
       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
@@ -2227,6 +2704,20 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2257,6 +2748,24 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/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,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/is-plain-object": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -2281,6 +2790,18 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -2358,10 +2879,10 @@
         "js-yaml": "bin/js-yaml.js"
       }
     },
-    "node_modules/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==",
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
       "dev": true
     },
     "node_modules/json-schema-traverse": {
@@ -2419,14 +2940,20 @@
       }
     },
     "node_modules/linkify-it": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
-      "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
       "dev": true,
       "dependencies": {
         "uc.micro": "^1.0.1"
       }
     },
+    "node_modules/listenercount": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
+      "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=",
+      "dev": true
+    },
     "node_modules/loader-runner": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
@@ -2466,6 +2993,22 @@
       "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
       "dev": true
     },
+    "node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/loose-envify": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -2497,14 +3040,14 @@
       "dev": true
     },
     "node_modules/markdown-it": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
-      "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
       "dev": true,
       "dependencies": {
-        "argparse": "^1.0.7",
-        "entities": "~2.0.0",
-        "linkify-it": "^2.0.0",
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
         "mdurl": "^1.0.1",
         "uc.micro": "^1.0.5"
       },
@@ -2512,16 +3055,25 @@
         "markdown-it": "bin/markdown-it.js"
       }
     },
-    "node_modules/markdown-it/node_modules/entities": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
-      "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
+    "node_modules/markdown-it/node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
       "dev": true
     },
+    "node_modules/markdown-it/node_modules/entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
     "node_modules/marked": {
-      "version": "4.0.6",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.6.tgz",
-      "integrity": "sha512-+H0bTf8DM8zLuFBUm/2VklxaCrwlBFgoJzHJcMZCnZ9cPgsllHwKpL6TPLdDeA38yPluMuVKOL1hO5w6HmG5Mg==",
+      "version": "4.0.16",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz",
+      "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==",
       "bin": {
         "marked": "bin/marked.js"
       },
@@ -2541,6 +3093,19 @@
       "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
       "dev": true
     },
+    "node_modules/micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dev": true,
+      "dependencies": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
     "node_modules/mime": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -2557,7 +3122,6 @@
       "version": "1.51.0",
       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
       "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
-      "dev": true,
       "engines": {
         "node": ">= 0.6"
       }
@@ -2566,7 +3130,6 @@
       "version": "2.1.34",
       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
       "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
-      "dev": true,
       "dependencies": {
         "mime-db": "1.51.0"
       },
@@ -2608,17 +3171,202 @@
       }
     },
     "node_modules/minimist": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
       "dev": true
     },
+    "node_modules/mkdirp": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
     "node_modules/mkdirp-classic": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
       "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
       "dev": true
     },
+    "node_modules/mocha": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
+      "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
+      "dev": true,
+      "dependencies": {
+        "@ungap/promise-all-settled": "1.1.2",
+        "ansi-colors": "4.1.1",
+        "browser-stdout": "1.3.1",
+        "chokidar": "3.5.3",
+        "debug": "4.3.3",
+        "diff": "5.0.0",
+        "escape-string-regexp": "4.0.0",
+        "find-up": "5.0.0",
+        "glob": "7.2.0",
+        "growl": "1.10.5",
+        "he": "1.2.0",
+        "js-yaml": "4.1.0",
+        "log-symbols": "4.1.0",
+        "minimatch": "4.2.1",
+        "ms": "2.1.3",
+        "nanoid": "3.3.1",
+        "serialize-javascript": "6.0.0",
+        "strip-json-comments": "3.1.1",
+        "supports-color": "8.1.1",
+        "which": "2.0.2",
+        "workerpool": "6.2.0",
+        "yargs": "16.2.0",
+        "yargs-parser": "20.2.4",
+        "yargs-unparser": "2.0.0"
+      },
+      "bin": {
+        "_mocha": "bin/_mocha",
+        "mocha": "bin/mocha"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/mochajs"
+      }
+    },
+    "node_modules/mocha/node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "node_modules/mocha/node_modules/diff": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/mocha/node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/mocha/node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/mocha/node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/minimatch": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
+      "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/mocha/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true
+    },
+    "node_modules/mocha/node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -2630,6 +3378,18 @@
       "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
       "dev": true
     },
+    "node_modules/nanoid": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
+      "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
+      "dev": true,
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
     "node_modules/napi-build-utils": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
@@ -2713,6 +3473,15 @@
       "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
       "dev": true
     },
+    "node_modules/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,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/npm-run-path": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -2858,11 +3627,23 @@
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
       "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
       "dev": true,
-      "dependencies": {
-        "callsites": "^3.0.0"
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-github-url": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz",
+      "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==",
+      "dev": true,
+      "bin": {
+        "parse-github-url": "cli.js"
       },
       "engines": {
-        "node": ">=6"
+        "node": ">=0.10.0"
       }
     },
     "node_modules/parse-semver": {
@@ -2943,6 +3724,18 @@
       "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
       "dev": true
     },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
     "node_modules/pkg-dir": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
@@ -3133,6 +3926,18 @@
       "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
       "dev": true
     },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
     "node_modules/rechoir": {
       "version": "0.7.1",
       "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
@@ -3162,6 +3967,15 @@
         "url": "https://github.com/sponsors/mysticatea"
       }
     },
+    "node_modules/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,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/require-from-string": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -3303,6 +4117,12 @@
       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
       "dev": true
     },
+    "node_modules/setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+      "dev": true
+    },
     "node_modules/shallow-clone": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
@@ -3377,9 +4197,9 @@
       ]
     },
     "node_modules/simple-get": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
-      "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
+      "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
       "dev": true,
       "dependencies": {
         "decompress-response": "^4.2.0",
@@ -3388,13 +4208,13 @@
       }
     },
     "node_modules/simple-git": {
-      "version": "2.48.0",
-      "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.48.0.tgz",
-      "integrity": "sha512-z4qtrRuaAFJS4PUd0g+xy7aN4y+RvEt/QTJpR184lhJguBA1S/LsVlvE/CM95RsYMOFJG3NGGDjqFCzKU19S/A==",
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.7.1.tgz",
+      "integrity": "sha512-+Osjtsumbtew2y9to0pOYjNzSIr4NkKGBg7Po5SUtjQhaJf2QBmiTX/9E9cv9rmc7oUiSGFIB9e7ys5ibnT9+A==",
       "dependencies": {
         "@kwsites/file-exists": "^1.1.1",
         "@kwsites/promise-deferred": "^1.1.1",
-        "debug": "^4.3.2"
+        "debug": "^4.3.3"
       },
       "funding": {
         "type": "github",
@@ -3730,6 +4550,52 @@
         "node": ">=8.17.0"
       }
     },
+    "node_modules/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,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
+      "dev": true
+    },
+    "node_modules/traverse": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+      "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/ts-loader": {
+      "version": "9.3.0",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.0.tgz",
+      "integrity": "sha512-2kLLAdAD+FCKijvGKi9sS0OzoqxLCF3CxHpok7rVgCZ5UldRzH0TkbwG9XECKjBzHsAewntC5oDaI/FwKzEUog==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "enhanced-resolve": "^5.0.0",
+        "micromatch": "^4.0.0",
+        "semver": "^7.3.4"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "typescript": "*",
+        "webpack": "^5.0.0"
+      }
+    },
     "node_modules/ts-node": {
       "version": "9.1.1",
       "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
@@ -3851,12 +4717,43 @@
       "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
       "dev": true
     },
+    "node_modules/uglify-js": {
+      "version": "3.15.4",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz",
+      "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==",
+      "dev": true,
+      "optional": true,
+      "bin": {
+        "uglifyjs": "bin/uglifyjs"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
     "node_modules/underscore": {
       "version": "1.13.1",
       "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz",
       "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==",
       "dev": true
     },
+    "node_modules/unzipper": {
+      "version": "0.10.11",
+      "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
+      "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
+      "dev": true,
+      "dependencies": {
+        "big-integer": "^1.6.17",
+        "binary": "~0.3.0",
+        "bluebird": "~3.4.1",
+        "buffer-indexof-polyfill": "~1.0.0",
+        "duplexer2": "~0.1.4",
+        "fstream": "^1.0.12",
+        "graceful-fs": "^4.2.2",
+        "listenercount": "~1.0.1",
+        "readable-stream": "~2.3.6",
+        "setimmediate": "~1.0.4"
+      }
+    },
     "node_modules/uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -3885,9 +4782,9 @@
       "dev": true
     },
     "node_modules/vsce": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz",
-      "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==",
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.7.0.tgz",
+      "integrity": "sha512-CKU34wrQlbKDeJCRBkd1a8iwF9EvNxcYMg9hAUH6AxFGR6Wo2IKWwt3cJIcusHxx6XdjDHWlfAS/fJN30uvVnA==",
       "dev": true,
       "dependencies": {
         "azure-devops-node-api": "^11.0.1",
@@ -3898,7 +4795,7 @@
         "hosted-git-info": "^4.0.2",
         "keytar": "^7.7.0",
         "leven": "^3.1.0",
-        "markdown-it": "^10.0.0",
+        "markdown-it": "^12.3.2",
         "mime": "^1.3.4",
         "minimatch": "^3.0.3",
         "parse-semver": "^1.1.1",
@@ -3980,14 +4877,20 @@
         "node": ">= 8"
       }
     },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
+      "dev": true
+    },
     "node_modules/webpack": {
-      "version": "5.65.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz",
-      "integrity": "sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw==",
+      "version": "5.72.1",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz",
+      "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==",
       "dev": true,
       "dependencies": {
-        "@types/eslint-scope": "^3.7.0",
-        "@types/estree": "^0.0.50",
+        "@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",
@@ -3995,13 +4898,13 @@
         "acorn-import-assertions": "^1.7.6",
         "browserslist": "^4.14.5",
         "chrome-trace-event": "^1.0.2",
-        "enhanced-resolve": "^5.8.3",
+        "enhanced-resolve": "^5.9.3",
         "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.4",
-        "json-parse-better-errors": "^1.0.2",
+        "graceful-fs": "^4.2.9",
+        "json-parse-even-better-errors": "^2.3.1",
         "loader-runner": "^4.2.0",
         "mime-types": "^2.1.27",
         "neo-async": "^2.6.2",
@@ -4009,7 +4912,7 @@
         "tapable": "^2.1.1",
         "terser-webpack-plugin": "^5.1.3",
         "watchpack": "^2.3.1",
-        "webpack-sources": "^3.2.2"
+        "webpack-sources": "^3.2.3"
       },
       "bin": {
         "webpack": "bin/webpack.js"
@@ -4028,15 +4931,15 @@
       }
     },
     "node_modules/webpack-cli": {
-      "version": "4.9.1",
-      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz",
-      "integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==",
+      "version": "4.9.2",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz",
+      "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==",
       "dev": true,
       "dependencies": {
         "@discoveryjs/json-ext": "^0.5.0",
-        "@webpack-cli/configtest": "^1.1.0",
-        "@webpack-cli/info": "^1.4.0",
-        "@webpack-cli/serve": "^1.6.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",
@@ -4093,14 +4996,24 @@
       }
     },
     "node_modules/webpack-sources": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.2.tgz",
-      "integrity": "sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw==",
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+      "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
       "dev": true,
       "engines": {
         "node": ">=10.13.0"
       }
     },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+      "dev": true,
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -4140,6 +5053,68 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
+    },
+    "node_modules/workerpool": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
+      "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
+      "dev": true
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
     "node_modules/wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -4168,12 +5143,63 @@
         "node": ">=4.0"
       }
     },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
+    "node_modules/yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "dev": true,
+      "dependencies": {
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs-unparser": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^6.0.0",
+        "decamelize": "^4.0.0",
+        "flat": "^5.0.2",
+        "is-plain-obj": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/yauzl": {
       "version": "2.10.0",
       "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
@@ -4201,6 +5227,18 @@
       "engines": {
         "node": ">=6"
       }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
     }
   },
   "dependencies": {
@@ -4335,6 +5373,12 @@
         "exenv-es6": "^1.1.1"
       }
     },
+    "@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true
+    },
     "@types/crypto-js": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz",
@@ -4342,9 +5386,9 @@
       "dev": true
     },
     "@types/eslint": {
-      "version": "8.2.1",
-      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz",
-      "integrity": "sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==",
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz",
+      "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==",
       "dev": true,
       "requires": {
         "@types/estree": "*",
@@ -4352,9 +5396,9 @@
       }
     },
     "@types/eslint-scope": {
-      "version": "3.7.1",
-      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz",
-      "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==",
+      "version": "3.7.3",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz",
+      "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==",
       "dev": true,
       "requires": {
         "@types/eslint": "*",
@@ -4368,11 +5412,21 @@
       "dev": true
     },
     "@types/estree": {
-      "version": "0.0.50",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
-      "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
+      "version": "0.0.51",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
+      "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
       "dev": true
     },
+    "@types/glob": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
+      "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
+      "dev": true,
+      "requires": {
+        "@types/minimatch": "*",
+        "@types/node": "*"
+      }
+    },
     "@types/json-schema": {
       "version": "7.0.9",
       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
@@ -4385,10 +5439,22 @@
       "integrity": "sha512-ZigEmCWdNUU7IjZEuQ/iaimYdDHWHfTe3kg8ORfKjyGYd9RWumPoOJRQXB0bO+XLkNwzCthW3wUIQtANaEZ1ag==",
       "dev": true
     },
+    "@types/minimatch": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
+      "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
+      "dev": true
+    },
+    "@types/mocha": {
+      "version": "9.1.1",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz",
+      "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==",
+      "dev": true
+    },
     "@types/node": {
-      "version": "12.20.47",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.47.tgz",
-      "integrity": "sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==",
+      "version": "14.18.18",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz",
+      "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==",
       "dev": true
     },
     "@types/node-fetch": {
@@ -4402,9 +5468,9 @@
       }
     },
     "@types/vscode": {
-      "version": "1.62.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.62.0.tgz",
-      "integrity": "sha512-iGlQJ1w5e3qPUryroO6v4lxg3ql1ztdTCwQW3xEwFawdyPLoeUSv48SYfMwc7kQA7h6ThUqflZIjgKAykeF9oA==",
+      "version": "1.67.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.67.0.tgz",
+      "integrity": "sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==",
       "dev": true
     },
     "@typescript-eslint/eslint-plugin": {
@@ -4478,6 +5544,24 @@
         "eslint-visitor-keys": "^1.1.0"
       }
     },
+    "@ungap/promise-all-settled": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+      "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+      "dev": true
+    },
+    "@vscode/test-electron": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.3.tgz",
+      "integrity": "sha512-ps/yJ/9ToUZtR1dHfWi1mDXtep1VoyyrmGKC3UnIbScToRQvbUjyy1VMqnMEW3EpMmC3g7+pyThIPtPyCLHyow==",
+      "dev": true,
+      "requires": {
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "rimraf": "^3.0.2",
+        "unzipper": "^0.10.11"
+      }
+    },
     "@vscode/webview-ui-toolkit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.0.0.tgz",
@@ -4635,25 +5719,25 @@
       }
     },
     "@webpack-cli/configtest": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz",
-      "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz",
+      "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==",
       "dev": true,
       "requires": {}
     },
     "@webpack-cli/info": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz",
-      "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==",
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz",
+      "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==",
       "dev": true,
       "requires": {
         "envinfo": "^7.7.3"
       }
     },
     "@webpack-cli/serve": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz",
-      "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==",
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz",
+      "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==",
       "dev": true,
       "requires": {}
     },
@@ -4689,6 +5773,15 @@
       "dev": true,
       "requires": {}
     },
+    "agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "requires": {
+        "debug": "4"
+      }
+    },
     "ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -4729,6 +5822,16 @@
         "color-convert": "^1.9.0"
       }
     },
+    "anymatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "dev": true,
+      "requires": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      }
+    },
     "aproba": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -4774,8 +5877,58 @@
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
-      "dev": true
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+    },
+    "auto-changelog": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.4.0.tgz",
+      "integrity": "sha512-vh17hko1c0ItsEcw6m7qPRf3m45u+XK5QyCrrBFViElZ8jnKrPC1roSznrd1fIB/0vR/zawdECCRJtTuqIXaJw==",
+      "dev": true,
+      "requires": {
+        "commander": "^7.2.0",
+        "handlebars": "^4.7.7",
+        "node-fetch": "^2.6.1",
+        "parse-github-url": "^1.0.2",
+        "semver": "^7.3.5"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+          "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+          "dev": true
+        },
+        "node-fetch": {
+          "version": "2.6.7",
+          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+          "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+          "dev": true,
+          "requires": {
+            "whatwg-url": "^5.0.0"
+          }
+        }
+      }
+    },
+    "axios": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+      "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+      "requires": {
+        "follow-redirects": "^1.14.9",
+        "form-data": "^4.0.0"
+      },
+      "dependencies": {
+        "form-data": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+          "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+          "requires": {
+            "asynckit": "^0.4.0",
+            "combined-stream": "^1.0.8",
+            "mime-types": "^2.1.12"
+          }
+        }
+      }
     },
     "azure-devops-node-api": {
       "version": "11.1.0",
@@ -4799,6 +5952,28 @@
       "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
       "dev": true
     },
+    "big-integer": {
+      "version": "1.6.51",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+      "dev": true
+    },
+    "binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
+      "dev": true,
+      "requires": {
+        "buffers": "~0.1.1",
+        "chainsaw": "~0.1.0"
+      }
+    },
+    "binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "dev": true
+    },
     "bl": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -4823,6 +5998,12 @@
         }
       }
     },
+    "bluebird": {
+      "version": "3.4.7",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+      "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
+      "dev": true
+    },
     "boolbase": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -4839,6 +6020,21 @@
         "concat-map": "0.0.1"
       }
     },
+    "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"
+      }
+    },
+    "browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "dev": true
+    },
     "browserslist": {
       "version": "4.18.1",
       "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz",
@@ -4874,6 +6070,18 @@
       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
       "dev": true
     },
+    "buffer-indexof-polyfill": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
+      "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
+      "dev": true
+    },
+    "buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
+      "dev": true
+    },
     "call-bind": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -4890,12 +6098,27 @@
       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
       "dev": true
     },
+    "camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true
+    },
     "caniuse-lite": {
       "version": "1.0.30001285",
       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz",
       "integrity": "sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q==",
       "dev": true
     },
+    "chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
+      "dev": true,
+      "requires": {
+        "traverse": ">=0.3.0 <0.4"
+      }
+    },
     "chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -4983,6 +6206,22 @@
         "domutils": "^2.7.0"
       }
     },
+    "chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "dev": true,
+      "requires": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "fsevents": "~2.3.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"
+      }
+    },
     "chownr": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
@@ -4995,6 +6234,17 @@
       "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
       "dev": true
     },
+    "cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "dev": true,
+      "requires": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
     "clone-deep": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -5037,7 +6287,6 @@
       "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"
       }
@@ -5125,6 +6374,12 @@
         "ms": "2.1.2"
       }
     },
+    "decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "dev": true
+    },
     "decompress-response": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
@@ -5149,8 +6404,7 @@
     "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
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
     },
     "delegates": {
       "version": "1.0.0",
@@ -5216,6 +6470,15 @@
         "domhandler": "^4.2.0"
       }
     },
+    "duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.2"
+      }
+    },
     "electron-to-chromium": {
       "version": "1.4.11",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.11.tgz",
@@ -5238,9 +6501,9 @@
       }
     },
     "enhanced-resolve": {
-      "version": "5.8.3",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz",
-      "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==",
+      "version": "5.9.3",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz",
+      "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==",
       "dev": true,
       "requires": {
         "graceful-fs": "^4.2.4",
@@ -5555,6 +6818,15 @@
         "flat-cache": "^3.0.4"
       }
     },
+    "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"
+      }
+    },
     "find-up": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -5565,6 +6837,12 @@
         "path-exists": "^4.0.0"
       }
     },
+    "flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true
+    },
     "flat-cache": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@@ -5581,6 +6859,11 @@
       "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
       "dev": true
     },
+    "follow-redirects": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz",
+      "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ=="
+    },
     "form-data": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
@@ -5612,6 +6895,36 @@
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
       "dev": true
     },
+    "fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "optional": true
+    },
+    "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"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "2.7.1",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        }
+      }
+    },
     "function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -5677,6 +6990,12 @@
         }
       }
     },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true
+    },
     "get-intrinsic": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
@@ -5739,11 +7058,30 @@
       }
     },
     "graceful-fs": {
-      "version": "4.2.8",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
-      "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==",
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
       "dev": true
     },
+    "growl": {
+      "version": "1.10.5",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+      "dev": true
+    },
+    "handlebars": {
+      "version": "4.7.7",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
+      "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.5",
+        "neo-async": "^2.6.0",
+        "source-map": "^0.6.1",
+        "uglify-js": "^3.1.4",
+        "wordwrap": "^1.0.0"
+      }
+    },
     "has": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -5771,6 +7109,12 @@
       "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
       "dev": true
     },
+    "he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true
+    },
     "hosted-git-info": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz",
@@ -5792,6 +7136,27 @@
         "entities": "^2.0.0"
       }
     },
+    "http-proxy-agent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "dev": true,
+      "requires": {
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
+      }
+    },
+    "https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "requires": {
+        "agent-base": "6",
+        "debug": "4"
+      }
+    },
     "human-signals": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -5869,6 +7234,15 @@
       "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz",
       "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ=="
     },
+    "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-core-module": {
       "version": "2.8.0",
       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
@@ -5878,6 +7252,11 @@
         "has": "^1.0.3"
       }
     },
+    "is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="
+    },
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -5899,6 +7278,18 @@
         "is-extglob": "^2.1.1"
       }
     },
+    "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
+    },
+    "is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true
+    },
     "is-plain-object": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -5914,6 +7305,12 @@
       "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
       "dev": true
     },
+    "is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true
+    },
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -5975,10 +7372,10 @@
         "esprima": "^4.0.0"
       }
     },
-    "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==",
+    "json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
       "dev": true
     },
     "json-schema-traverse": {
@@ -6026,14 +7423,20 @@
       }
     },
     "linkify-it": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
-      "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
       "dev": true,
       "requires": {
         "uc.micro": "^1.0.1"
       }
     },
+    "listenercount": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
+      "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=",
+      "dev": true
+    },
     "loader-runner": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
@@ -6067,6 +7470,16 @@
       "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
       "dev": true
     },
+    "log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      }
+    },
     "loose-envify": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -6092,30 +7505,36 @@
       "dev": true
     },
     "markdown-it": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
-      "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
       "dev": true,
       "requires": {
-        "argparse": "^1.0.7",
-        "entities": "~2.0.0",
-        "linkify-it": "^2.0.0",
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
         "mdurl": "^1.0.1",
         "uc.micro": "^1.0.5"
       },
       "dependencies": {
+        "argparse": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+          "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+          "dev": true
+        },
         "entities": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
-          "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+          "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
           "dev": true
         }
       }
     },
     "marked": {
-      "version": "4.0.6",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.6.tgz",
-      "integrity": "sha512-+H0bTf8DM8zLuFBUm/2VklxaCrwlBFgoJzHJcMZCnZ9cPgsllHwKpL6TPLdDeA38yPluMuVKOL1hO5w6HmG5Mg=="
+      "version": "4.0.16",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz",
+      "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA=="
     },
     "mdurl": {
       "version": "1.0.1",
@@ -6129,6 +7548,16 @@
       "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
       "dev": true
     },
+    "micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dev": true,
+      "requires": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      }
+    },
     "mime": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -6138,14 +7567,12 @@
     "mime-db": {
       "version": "1.51.0",
       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
-      "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
-      "dev": true
+      "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
     },
     "mime-types": {
       "version": "2.1.34",
       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
       "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
-      "dev": true,
       "requires": {
         "mime-db": "1.51.0"
       }
@@ -6172,17 +7599,148 @@
       }
     },
     "minimist": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
       "dev": true
     },
+    "mkdirp": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.6"
+      }
+    },
     "mkdirp-classic": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
       "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
       "dev": true
     },
+    "mocha": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
+      "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
+      "dev": true,
+      "requires": {
+        "@ungap/promise-all-settled": "1.1.2",
+        "ansi-colors": "4.1.1",
+        "browser-stdout": "1.3.1",
+        "chokidar": "3.5.3",
+        "debug": "4.3.3",
+        "diff": "5.0.0",
+        "escape-string-regexp": "4.0.0",
+        "find-up": "5.0.0",
+        "glob": "7.2.0",
+        "growl": "1.10.5",
+        "he": "1.2.0",
+        "js-yaml": "4.1.0",
+        "log-symbols": "4.1.0",
+        "minimatch": "4.2.1",
+        "ms": "2.1.3",
+        "nanoid": "3.3.1",
+        "serialize-javascript": "6.0.0",
+        "strip-json-comments": "3.1.1",
+        "supports-color": "8.1.1",
+        "which": "2.0.2",
+        "workerpool": "6.2.0",
+        "yargs": "16.2.0",
+        "yargs-parser": "20.2.4",
+        "yargs-unparser": "2.0.0"
+      },
+      "dependencies": {
+        "argparse": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+          "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+          "dev": true
+        },
+        "diff": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+          "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+          "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^6.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+          "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+          "dev": true,
+          "requires": {
+            "argparse": "^2.0.1"
+          }
+        },
+        "locate-path": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+          "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^5.0.0"
+          }
+        },
+        "minimatch": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
+          "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        },
+        "p-limit": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+          "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+          "dev": true,
+          "requires": {
+            "yocto-queue": "^0.1.0"
+          }
+        },
+        "p-locate": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+          "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^3.0.2"
+          }
+        },
+        "supports-color": {
+          "version": "8.1.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
     "ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -6194,6 +7752,12 @@
       "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
       "dev": true
     },
+    "nanoid": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
+      "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
+      "dev": true
+    },
     "napi-build-utils": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
@@ -6256,6 +7820,12 @@
       "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
       "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
+    },
     "npm-run-path": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -6369,6 +7939,12 @@
         "callsites": "^3.0.0"
       }
     },
+    "parse-github-url": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz",
+      "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==",
+      "dev": true
+    },
     "parse-semver": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
@@ -6437,6 +8013,12 @@
       "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
       "dev": true
     },
+    "picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true
+    },
     "pkg-dir": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
@@ -6586,6 +8168,15 @@
         }
       }
     },
+    "readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "requires": {
+        "picomatch": "^2.2.1"
+      }
+    },
     "rechoir": {
       "version": "0.7.1",
       "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
@@ -6606,6 +8197,12 @@
       "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
       "dev": true
     },
+    "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-from-string": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -6701,6 +8298,12 @@
       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
       "dev": true
     },
+    "setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+      "dev": true
+    },
     "shallow-clone": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
@@ -6749,9 +8352,9 @@
       "dev": true
     },
     "simple-get": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
-      "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
+      "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
       "dev": true,
       "requires": {
         "decompress-response": "^4.2.0",
@@ -6760,13 +8363,13 @@
       }
     },
     "simple-git": {
-      "version": "2.48.0",
-      "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.48.0.tgz",
-      "integrity": "sha512-z4qtrRuaAFJS4PUd0g+xy7aN4y+RvEt/QTJpR184lhJguBA1S/LsVlvE/CM95RsYMOFJG3NGGDjqFCzKU19S/A==",
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.7.1.tgz",
+      "integrity": "sha512-+Osjtsumbtew2y9to0pOYjNzSIr4NkKGBg7Po5SUtjQhaJf2QBmiTX/9E9cv9rmc7oUiSGFIB9e7ys5ibnT9+A==",
       "requires": {
         "@kwsites/file-exists": "^1.1.1",
         "@kwsites/promise-deferred": "^1.1.1",
-        "debug": "^4.3.2"
+        "debug": "^4.3.3"
       }
     },
     "slice-ansi": {
@@ -7015,6 +8618,39 @@
         "rimraf": "^3.0.0"
       }
     },
+    "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"
+      }
+    },
+    "tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
+      "dev": true
+    },
+    "traverse": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+      "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=",
+      "dev": true
+    },
+    "ts-loader": {
+      "version": "9.3.0",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.0.tgz",
+      "integrity": "sha512-2kLLAdAD+FCKijvGKi9sS0OzoqxLCF3CxHpok7rVgCZ5UldRzH0TkbwG9XECKjBzHsAewntC5oDaI/FwKzEUog==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "enhanced-resolve": "^5.0.0",
+        "micromatch": "^4.0.0",
+        "semver": "^7.3.4"
+      }
+    },
     "ts-node": {
       "version": "9.1.1",
       "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
@@ -7096,12 +8732,37 @@
       "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
       "dev": true
     },
+    "uglify-js": {
+      "version": "3.15.4",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz",
+      "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==",
+      "dev": true,
+      "optional": true
+    },
     "underscore": {
       "version": "1.13.1",
       "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz",
       "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==",
       "dev": true
     },
+    "unzipper": {
+      "version": "0.10.11",
+      "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
+      "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
+      "dev": true,
+      "requires": {
+        "big-integer": "^1.6.17",
+        "binary": "~0.3.0",
+        "bluebird": "~3.4.1",
+        "buffer-indexof-polyfill": "~1.0.0",
+        "duplexer2": "~0.1.4",
+        "fstream": "^1.0.12",
+        "graceful-fs": "^4.2.2",
+        "listenercount": "~1.0.1",
+        "readable-stream": "~2.3.6",
+        "setimmediate": "~1.0.4"
+      }
+    },
     "uri-js": {
       "version": "4.4.1",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -7130,9 +8791,9 @@
       "dev": true
     },
     "vsce": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz",
-      "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==",
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.7.0.tgz",
+      "integrity": "sha512-CKU34wrQlbKDeJCRBkd1a8iwF9EvNxcYMg9hAUH6AxFGR6Wo2IKWwt3cJIcusHxx6XdjDHWlfAS/fJN30uvVnA==",
       "dev": true,
       "requires": {
         "azure-devops-node-api": "^11.0.1",
@@ -7143,7 +8804,7 @@
         "hosted-git-info": "^4.0.2",
         "keytar": "^7.7.0",
         "leven": "^3.1.0",
-        "markdown-it": "^10.0.0",
+        "markdown-it": "^12.3.2",
         "mime": "^1.3.4",
         "minimatch": "^3.0.3",
         "parse-semver": "^1.1.1",
@@ -7203,14 +8864,20 @@
       "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
       "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
     },
+    "webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
+      "dev": true
+    },
     "webpack": {
-      "version": "5.65.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz",
-      "integrity": "sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw==",
+      "version": "5.72.1",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz",
+      "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==",
       "dev": true,
       "requires": {
-        "@types/eslint-scope": "^3.7.0",
-        "@types/estree": "^0.0.50",
+        "@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",
@@ -7218,13 +8885,13 @@
         "acorn-import-assertions": "^1.7.6",
         "browserslist": "^4.14.5",
         "chrome-trace-event": "^1.0.2",
-        "enhanced-resolve": "^5.8.3",
+        "enhanced-resolve": "^5.9.3",
         "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.4",
-        "json-parse-better-errors": "^1.0.2",
+        "graceful-fs": "^4.2.9",
+        "json-parse-even-better-errors": "^2.3.1",
         "loader-runner": "^4.2.0",
         "mime-types": "^2.1.27",
         "neo-async": "^2.6.2",
@@ -7232,19 +8899,19 @@
         "tapable": "^2.1.1",
         "terser-webpack-plugin": "^5.1.3",
         "watchpack": "^2.3.1",
-        "webpack-sources": "^3.2.2"
+        "webpack-sources": "^3.2.3"
       }
     },
     "webpack-cli": {
-      "version": "4.9.1",
-      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz",
-      "integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==",
+      "version": "4.9.2",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz",
+      "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==",
       "dev": true,
       "requires": {
         "@discoveryjs/json-ext": "^0.5.0",
-        "@webpack-cli/configtest": "^1.1.0",
-        "@webpack-cli/info": "^1.4.0",
-        "@webpack-cli/serve": "^1.6.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",
@@ -7274,11 +8941,21 @@
       }
     },
     "webpack-sources": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.2.tgz",
-      "integrity": "sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw==",
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+      "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
       "dev": true
     },
+    "whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+      "dev": true,
+      "requires": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
     "which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -7309,6 +8986,55 @@
       "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
       "dev": true
     },
+    "wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
+    },
+    "workerpool": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
+      "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
+      "dev": true
+    },
+    "wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        }
+      }
+    },
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -7331,12 +9057,51 @@
       "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
       "dev": true
     },
+    "y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true
+    },
     "yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
+    "yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "dev": true,
+      "requires": {
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      }
+    },
+    "yargs-parser": {
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "dev": true
+    },
+    "yargs-unparser": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^6.0.0",
+        "decamelize": "^4.0.0",
+        "flat": "^5.0.2",
+        "is-plain-obj": "^2.1.0"
+      }
+    },
     "yauzl": {
       "version": "2.10.0",
       "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
@@ -7361,6 +9126,12 @@
       "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
       "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
       "dev": true
+    },
+    "yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true
     }
   }
 }
diff --git a/deadlock-plugins/deadlock-extension/package.json b/deadlock-plugins/deadlock-extension/package.json
index 69aa8ecd31ee4a426c3aee800ade330a3baf4327..cfd3d4b0397ecd22584c5d33ef5604f3bc6630c0 100644
--- a/deadlock-plugins/deadlock-extension/package.json
+++ b/deadlock-plugins/deadlock-extension/package.json
@@ -1,10 +1,11 @@
 {
   "name": "deadlock-coding",
   "description": "Deadlock Coding",
-  "version": "0.0.2",
+  "version": "0.1.9",
   "publisher": "Deadlock",
+  "icon": "media/logo.png",
   "engines": {
-    "vscode": "^1.66.0"
+    "vscode": ">=1.66.0"
   },
   "categories": [
     "Other"
@@ -16,11 +17,7 @@
     "onWebviewPanel:deadlockHelp",
     "onStartupFinished"
   ],
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/microsoft/vscode-extension-samples.git"
-  },
-  "main": "./out/main.js",
+  "main": "./dist/extension.js",
   "contributes": {
     "commands": [
       {
@@ -64,7 +61,7 @@
         {
           "id": "help",
           "name": "Help",
-          "visibility": "collapsed"
+          "visibility": "visible"
         }
       ]
     },
@@ -85,43 +82,61 @@
     }
   },
   "scripts": {
-    "vsce": "vsce package",
+    "vsce-package": "vsce package --allow-missing-repository",
+    "vsce-publish": "vsce publish --allow-missing-repository",
+    "vscode:prepackage": "npm run build-extension",
+    "compile": "webpack",
     "esbuild-base": "esbuild --bundle --format=cjs --platform=node",
-    "build-extension": "npm run esbuild-base -- --external:vscode ./src/extension.ts --outfile=out/main.js --minify",
     "build-recorder": "npm run esbuild-base -- ./src/recorder/index.ts --outfile=out/recorder.js --minify",
-    "build-preStop": "npm run esbuild-base -- ./src/recorder/preStop.ts --outfile=out/preStop.js --minify",
     "esbuild": "npm run esbuild-base -- --sourcemap",
-    "esbuild-watch": "npm run esbuild-base -- --sourcemap --watch",
-    "lint": "eslint . --ext .ts,.tsx",
-    "watch": "tsc -w -p ./"
+    "watch": "webpack --watch",
+    "build-extension": "webpack --mode production --devtool hidden-source-map",
+    "compile-tests": "tsc -p . --outDir out",
+    "watch-tests": "tsc -p . -w --outDir out",
+    "pretest": "npm run compile-tests && npm run compile && npm run lint",
+    "lint": "eslint src --ext ts",
+    "test": "node ./out/test/runTest.js",
+    "postversion": "git add package*.json && auto-changelog -p && git add CHANGELOG.md && git commit -m \"build: $npm_package_version\""
   },
   "dependencies": {
     "@vscode/webview-ui-toolkit": "^1.0.0",
     "async": "^3.2.2",
+    "axios": "^0.27.2",
     "crypto-js": "^4.1.1",
     "date-fns": "^2.27.0",
     "inversify": "^6.0.1",
+    "is-docker": "^3.0.0",
     "marked": "^4.0.6",
     "node-fetch": "^3.2.3",
     "reflect-metadata": "^0.1.13",
-    "simple-git": "^2.48.0"
+    "simple-git": "^3.7.0"
   },
   "devDependencies": {
+    "@types/glob": "^7.2.0",
+    "@types/mocha": "^9.1.0",
     "@types/crypto-js": "^4.1.1",
     "@types/marked": "^4.0.1",
-    "@types/node": "^12.20.47",
+    "@types/node": "14.x",
     "@types/node-fetch": "^2.6.1",
-    "@types/vscode": "^1.51.0",
-    "@typescript-eslint/eslint-plugin": "^3.10.1",
-    "@typescript-eslint/parser": "^3.10.1",
+    "@types/vscode": "^1.66.0",
+    "auto-changelog": "^2.4.0",
     "esbuild": "^0.14.2",
-    "eslint": "^7.32.0",
     "prettier": "2.6.2",
     "terser-webpack-plugin": "^5.2.5",
     "ts-node": "^9.1.1",
+    "vsce": "^2.7.0",
     "typescript": "^3.9.10",
-    "vsce": "^2.5.1",
-    "webpack": "^5.65.0",
-    "webpack-cli": "^4.9.1"
-  }
+    "ts-loader": "^9.2.8",
+    "webpack": "^5.70.0",
+    "webpack-cli": "^4.9.2",
+    "@typescript-eslint/eslint-plugin": "^3.10.1",
+    "@typescript-eslint/parser": "^3.10.1",
+    "eslint": "^7.32.0",
+    "glob": "^7.2.0",
+    "mocha": "^9.2.2",
+    "@vscode/test-electron": "^2.1.3"
+  },
+  "extensionPack": [
+    "ms-vscode-remote.remote-containers"
+  ]
 }
diff --git a/deadlock-plugins/deadlock-extension/resources/dark/help.svg b/deadlock-plugins/deadlock-extension/resources/dark/help.svg
index 87a05d2aee68aec706cc1c02179671239f210d43..7d115def191648731c120ebc40a7c742792ffeb5 100644
--- a/deadlock-plugins/deadlock-extension/resources/dark/help.svg
+++ b/deadlock-plugins/deadlock-extension/resources/dark/help.svg
@@ -1 +1,3 @@
-<?xml version="1.0" ?><!DOCTYPE svg  PUBLIC '-//W3C//DTD SVG 1.1//EN'  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 48 48" height="48px" id="Layer_3" version="1.1" viewBox="0 0 48 48" width="48px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><path d="M26.456,8.366c1.152,0,2.209-0.407,3.161-1.22c0.943-0.812,1.523-1.799,1.731-2.951   c0.195-1.16-0.048-2.138-0.764-2.951c-0.714-0.821-1.648-1.228-2.803-1.228c-1.159,0-2.214,0.407-3.158,1.228   c-0.955,0.813-1.535,1.792-1.732,2.951c-0.143,1.151,0.133,2.139,0.812,2.951C24.384,7.959,25.305,8.366,26.456,8.366z" fill="#241F20"/><path d="M36.68,37.971c0-0.352-0.462-0.712-1.361-1.088c-0.105,0.152-0.211,0.282-0.316,0.435   c-0.627,0.798-2.965,3.613-6.008,5.3c-0.02,0.008-0.036,0.016-0.048,0.027c-0.265,0.141-0.536,0.246-0.808,0.371   c-0.803,0.286-1.552,0.36-1.793,0.38c-0.683-0.09-1.053-0.567-1.053-1.471c0-0.747,0.219-2.222,0.663-4.439l0.51-2.237   l2.083-10.001c0.339-1.705,0.521-2.649,0.562-2.835l0.454-2.339c0.268-1.449,0.404-2.406,0.404-2.873   c0-0.894-0.224-1.572-0.579-2.124c-0.031-0.08-0.074-0.161-0.133-0.245c-0.054-0.064-0.107-0.121-0.164-0.18   c-0.062-0.066-0.095-0.129-0.179-0.198c-0.888-0.726-1.715-0.933-2.287-0.979l0.01-0.016c0,0-3.759-0.286-9.326,3.383   c-0.081,0.054-0.13,0.09-0.204,0.141c-1.507,0.954-2.712,1.913-3.547,2.681c-0.642,0.547-1.135,1.058-1.5,1.533   c0,0.002-0.018,0.021-0.018,0.021l0.004-0.002c-0.476,0.624-0.726,1.193-0.726,1.695c0,0.397,0.32,0.794,0.958,1.189   c0,0,2.392-3.086,6.41-5.096c0.304-0.131,1.076-0.45,1.755-0.627c0.316-0.073,0.915-0.129,1.298,0.187   c0.274,0.284,0.456,0.683,0.456,1.301c0,0.563-0.085,1.243-0.256,2.061l-0.407,1.926l-0.507,2.407l-1.984,9.517   c-1.015,4.916-1.523,7.857-1.523,8.815c0,2.261,1.237,3.392,3.71,3.392c1.12,0,2.274-0.203,3.455-0.566   c0.008,0,0.012,0.004,0.02,0.007c0.081-0.027,0.155-0.059,0.232-0.085c0.196-0.063,0.394-0.138,0.59-0.213   c5.578-2.076,9.248-6.257,10.359-7.657c0.098-0.118,0.18-0.23,0.262-0.337c0.062-0.086,0.102-0.145,0.102-0.145h-0.004   C36.527,38.573,36.68,38.229,36.68,37.971z" fill="#241F20"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" ?><!DOCTYPE svg  PUBLIC '-//W3C//DTD SVG 1.1//EN'  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
+<svg enable-background="new 0 0 48 48" height="48px" id="Layer_3" version="1.1" viewBox="0 0 48 48" width="48px"
+     xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g><path d="M26.456,8.366c1.152,0,2.209-0.407,3.161-1.22c0.943-0.812,1.523-1.799,1.731-2.951   c0.195-1.16-0.048-2.138-0.764-2.951c-0.714-0.821-1.648-1.228-2.803-1.228c-1.159,0-2.214,0.407-3.158,1.228   c-0.955,0.813-1.535,1.792-1.732,2.951c-0.143,1.151,0.133,2.139,0.812,2.951C24.384,7.959,25.305,8.366,26.456,8.366z" fill="#241F20"/><path d="M36.68,37.971c0-0.352-0.462-0.712-1.361-1.088c-0.105,0.152-0.211,0.282-0.316,0.435   c-0.627,0.798-2.965,3.613-6.008,5.3c-0.02,0.008-0.036,0.016-0.048,0.027c-0.265,0.141-0.536,0.246-0.808,0.371   c-0.803,0.286-1.552,0.36-1.793,0.38c-0.683-0.09-1.053-0.567-1.053-1.471c0-0.747,0.219-2.222,0.663-4.439l0.51-2.237   l2.083-10.001c0.339-1.705,0.521-2.649,0.562-2.835l0.454-2.339c0.268-1.449,0.404-2.406,0.404-2.873   c0-0.894-0.224-1.572-0.579-2.124c-0.031-0.08-0.074-0.161-0.133-0.245c-0.054-0.064-0.107-0.121-0.164-0.18   c-0.062-0.066-0.095-0.129-0.179-0.198c-0.888-0.726-1.715-0.933-2.287-0.979l0.01-0.016c0,0-3.759-0.286-9.326,3.383   c-0.081,0.054-0.13,0.09-0.204,0.141c-1.507,0.954-2.712,1.913-3.547,2.681c-0.642,0.547-1.135,1.058-1.5,1.533   c0,0.002-0.018,0.021-0.018,0.021l0.004-0.002c-0.476,0.624-0.726,1.193-0.726,1.695c0,0.397,0.32,0.794,0.958,1.189   c0,0,2.392-3.086,6.41-5.096c0.304-0.131,1.076-0.45,1.755-0.627c0.316-0.073,0.915-0.129,1.298,0.187   c0.274,0.284,0.456,0.683,0.456,1.301c0,0.563-0.085,1.243-0.256,2.061l-0.407,1.926l-0.507,2.407l-1.984,9.517   c-1.015,4.916-1.523,7.857-1.523,8.815c0,2.261,1.237,3.392,3.71,3.392c1.12,0,2.274-0.203,3.455-0.566   c0.008,0,0.012,0.004,0.02,0.007c0.081-0.027,0.155-0.059,0.232-0.085c0.196-0.063,0.394-0.138,0.59-0.213   c5.578-2.076,9.248-6.257,10.359-7.657c0.098-0.118,0.18-0.23,0.262-0.337c0.062-0.086,0.102-0.145,0.102-0.145h-0.004   C36.527,38.573,36.68,38.229,36.68,37.971z" fill="#241F20"/></g></svg>
\ No newline at end of file
diff --git a/deadlock-plugins/deadlock-extension/resources/js/gettingStartedView.js b/deadlock-plugins/deadlock-extension/resources/js/gettingStartedView.js
index 363a55f54e7adbcc2c6d4ca27ec46a730a2e4b81..547953b63bc964364cd695380fdad8a1982613d7 100644
--- a/deadlock-plugins/deadlock-extension/resources/js/gettingStartedView.js
+++ b/deadlock-plugins/deadlock-extension/resources/js/gettingStartedView.js
@@ -1,4 +1,3 @@
-// This file is used by gettingStarted via a <script> tag
 const vscode = acquireVsCodeApi();
 
 function launchChooseMissionWorkdirAction() {
diff --git a/deadlock-plugins/deadlock-extension/resources/light/help.svg b/deadlock-plugins/deadlock-extension/resources/light/help.svg
index 87a05d2aee68aec706cc1c02179671239f210d43..7d115def191648731c120ebc40a7c742792ffeb5 100644
--- a/deadlock-plugins/deadlock-extension/resources/light/help.svg
+++ b/deadlock-plugins/deadlock-extension/resources/light/help.svg
@@ -1 +1,3 @@
-<?xml version="1.0" ?><!DOCTYPE svg  PUBLIC '-//W3C//DTD SVG 1.1//EN'  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 48 48" height="48px" id="Layer_3" version="1.1" viewBox="0 0 48 48" width="48px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><path d="M26.456,8.366c1.152,0,2.209-0.407,3.161-1.22c0.943-0.812,1.523-1.799,1.731-2.951   c0.195-1.16-0.048-2.138-0.764-2.951c-0.714-0.821-1.648-1.228-2.803-1.228c-1.159,0-2.214,0.407-3.158,1.228   c-0.955,0.813-1.535,1.792-1.732,2.951c-0.143,1.151,0.133,2.139,0.812,2.951C24.384,7.959,25.305,8.366,26.456,8.366z" fill="#241F20"/><path d="M36.68,37.971c0-0.352-0.462-0.712-1.361-1.088c-0.105,0.152-0.211,0.282-0.316,0.435   c-0.627,0.798-2.965,3.613-6.008,5.3c-0.02,0.008-0.036,0.016-0.048,0.027c-0.265,0.141-0.536,0.246-0.808,0.371   c-0.803,0.286-1.552,0.36-1.793,0.38c-0.683-0.09-1.053-0.567-1.053-1.471c0-0.747,0.219-2.222,0.663-4.439l0.51-2.237   l2.083-10.001c0.339-1.705,0.521-2.649,0.562-2.835l0.454-2.339c0.268-1.449,0.404-2.406,0.404-2.873   c0-0.894-0.224-1.572-0.579-2.124c-0.031-0.08-0.074-0.161-0.133-0.245c-0.054-0.064-0.107-0.121-0.164-0.18   c-0.062-0.066-0.095-0.129-0.179-0.198c-0.888-0.726-1.715-0.933-2.287-0.979l0.01-0.016c0,0-3.759-0.286-9.326,3.383   c-0.081,0.054-0.13,0.09-0.204,0.141c-1.507,0.954-2.712,1.913-3.547,2.681c-0.642,0.547-1.135,1.058-1.5,1.533   c0,0.002-0.018,0.021-0.018,0.021l0.004-0.002c-0.476,0.624-0.726,1.193-0.726,1.695c0,0.397,0.32,0.794,0.958,1.189   c0,0,2.392-3.086,6.41-5.096c0.304-0.131,1.076-0.45,1.755-0.627c0.316-0.073,0.915-0.129,1.298,0.187   c0.274,0.284,0.456,0.683,0.456,1.301c0,0.563-0.085,1.243-0.256,2.061l-0.407,1.926l-0.507,2.407l-1.984,9.517   c-1.015,4.916-1.523,7.857-1.523,8.815c0,2.261,1.237,3.392,3.71,3.392c1.12,0,2.274-0.203,3.455-0.566   c0.008,0,0.012,0.004,0.02,0.007c0.081-0.027,0.155-0.059,0.232-0.085c0.196-0.063,0.394-0.138,0.59-0.213   c5.578-2.076,9.248-6.257,10.359-7.657c0.098-0.118,0.18-0.23,0.262-0.337c0.062-0.086,0.102-0.145,0.102-0.145h-0.004   C36.527,38.573,36.68,38.229,36.68,37.971z" fill="#241F20"/></g></svg>
\ No newline at end of file
+<?xml version="1.0" ?><!DOCTYPE svg  PUBLIC '-//W3C//DTD SVG 1.1//EN'  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
+<svg enable-background="new 0 0 48 48" height="48px" id="Layer_3" version="1.1" viewBox="0 0 48 48" width="48px"
+     xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g><path d="M26.456,8.366c1.152,0,2.209-0.407,3.161-1.22c0.943-0.812,1.523-1.799,1.731-2.951   c0.195-1.16-0.048-2.138-0.764-2.951c-0.714-0.821-1.648-1.228-2.803-1.228c-1.159,0-2.214,0.407-3.158,1.228   c-0.955,0.813-1.535,1.792-1.732,2.951c-0.143,1.151,0.133,2.139,0.812,2.951C24.384,7.959,25.305,8.366,26.456,8.366z" fill="#241F20"/><path d="M36.68,37.971c0-0.352-0.462-0.712-1.361-1.088c-0.105,0.152-0.211,0.282-0.316,0.435   c-0.627,0.798-2.965,3.613-6.008,5.3c-0.02,0.008-0.036,0.016-0.048,0.027c-0.265,0.141-0.536,0.246-0.808,0.371   c-0.803,0.286-1.552,0.36-1.793,0.38c-0.683-0.09-1.053-0.567-1.053-1.471c0-0.747,0.219-2.222,0.663-4.439l0.51-2.237   l2.083-10.001c0.339-1.705,0.521-2.649,0.562-2.835l0.454-2.339c0.268-1.449,0.404-2.406,0.404-2.873   c0-0.894-0.224-1.572-0.579-2.124c-0.031-0.08-0.074-0.161-0.133-0.245c-0.054-0.064-0.107-0.121-0.164-0.18   c-0.062-0.066-0.095-0.129-0.179-0.198c-0.888-0.726-1.715-0.933-2.287-0.979l0.01-0.016c0,0-3.759-0.286-9.326,3.383   c-0.081,0.054-0.13,0.09-0.204,0.141c-1.507,0.954-2.712,1.913-3.547,2.681c-0.642,0.547-1.135,1.058-1.5,1.533   c0,0.002-0.018,0.021-0.018,0.021l0.004-0.002c-0.476,0.624-0.726,1.193-0.726,1.695c0,0.397,0.32,0.794,0.958,1.189   c0,0,2.392-3.086,6.41-5.096c0.304-0.131,1.076-0.45,1.755-0.627c0.316-0.073,0.915-0.129,1.298,0.187   c0.274,0.284,0.456,0.683,0.456,1.301c0,0.563-0.085,1.243-0.256,2.061l-0.407,1.926l-0.507,2.407l-1.984,9.517   c-1.015,4.916-1.523,7.857-1.523,8.815c0,2.261,1.237,3.392,3.71,3.392c1.12,0,2.274-0.203,3.455-0.566   c0.008,0,0.012,0.004,0.02,0.007c0.081-0.027,0.155-0.059,0.232-0.085c0.196-0.063,0.394-0.138,0.59-0.213   c5.578-2.076,9.248-6.257,10.359-7.657c0.098-0.118,0.18-0.23,0.262-0.337c0.062-0.086,0.102-0.145,0.102-0.145h-0.004   C36.527,38.573,36.68,38.229,36.68,37.971z" fill="#241F20"/></g></svg>
\ No newline at end of file
diff --git a/deadlock-plugins/deadlock-extension/resources/styles/gettingStartedView.css b/deadlock-plugins/deadlock-extension/resources/styles/gettingStartedView.css
index 5ae4f6fcf2fff5cd84531b5ab0e3f00fa46cf26f..afd0301f87f3b840c5beade48a0660955d2c0e82 100644
--- a/deadlock-plugins/deadlock-extension/resources/styles/gettingStartedView.css
+++ b/deadlock-plugins/deadlock-extension/resources/styles/gettingStartedView.css
@@ -1,5 +1,3 @@
-/* This file is used by gettingStarted via a <style> tag */
-
 .deadlock-getting-started-card-container {
   display: flex;
   justify-content: center;
diff --git a/deadlock-plugins/deadlock-extension/setup-dev-env.sh b/deadlock-plugins/deadlock-extension/setup-dev-env.sh
index fcd5d04ba4016f9026efbb77389456e196f77ee2..8689677d598142b5a7fac45c33b54ac3c242c415 100755
--- a/deadlock-plugins/deadlock-extension/setup-dev-env.sh
+++ b/deadlock-plugins/deadlock-extension/setup-dev-env.sh
@@ -6,4 +6,4 @@
 mkdir -p /home/$USER/deadlock-extension/project
 mkdir -p /home/$USER/deadlock-extension/project-theia
 
-cp -R ./dev/* /home/$USER/deadlock-extension
+cp -R ./dev/ressources/* /home/$USER/deadlock-extension
diff --git a/deadlock-plugins/deadlock-extension/src/config.prod.ts b/deadlock-plugins/deadlock-extension/src/config.prod.ts
index 46ee6889446bcf153f9619125c3ab2bd4d753d65..cf6b1eca8dd4876a5ebd91f6bde4341be0003bc1 100644
--- a/deadlock-plugins/deadlock-extension/src/config.prod.ts
+++ b/deadlock-plugins/deadlock-extension/src/config.prod.ts
@@ -2,4 +2,11 @@ export const KEYCLOAK_DEVICE_AUTH_URL =
   'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/auth/device';
 export const KEYCLOAK_TOKEN_CREATE_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token';
 export const KEYCLOAK_USER_INFO_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo';
+export const REGISTRY_MISSION_URL = 'registry.takima.io/deadlock/deadlock-challenges';
 export const REJECT_UNAUTHORIZED = true;
+export const ENABLE_AUTOMATIC_SAVE = true;
+export const ENABLE_RECORDER_HTTP_SERVER = false;
+export const RECORDER_HTTP_SERVER_PORT = 8751;
+export const RECORDER_HTTP_SERVER_URL = `http://localhost:${RECORDER_HTTP_SERVER_PORT}`;
+export const API_URL = 'https://api.deadlock.io/';
+export const API_QUERY_REFERER = 'https://takima.deadlock.io';
diff --git a/deadlock-plugins/deadlock-extension/src/config.staging.ts b/deadlock-plugins/deadlock-extension/src/config.staging.ts
index e8ddb5e90e01601adc2b4f79ee07d241551c535b..912c56c27d281d634df899e61b57166d2fc2a50a 100644
--- a/deadlock-plugins/deadlock-extension/src/config.staging.ts
+++ b/deadlock-plugins/deadlock-extension/src/config.staging.ts
@@ -4,4 +4,11 @@ export const KEYCLOAK_TOKEN_CREATE_URL =
   'https://auth.staging.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token';
 export const KEYCLOAK_USER_INFO_URL =
   'https://auth.staging.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo';
+export const REGISTRY_MISSION_URL = 'registry.takima.io/deadlock/deadlock-challenges';
 export const REJECT_UNAUTHORIZED = true;
+export const ENABLE_AUTOMATIC_SAVE = true;
+export const ENABLE_RECORDER_HTTP_SERVER = false;
+export const RECORDER_HTTP_SERVER_PORT = 8751;
+export const RECORDER_HTTP_SERVER_URL = `http://localhost:${RECORDER_HTTP_SERVER_PORT}`;
+export const API_URL = 'https://api.staging.deadlock.io/';
+export const API_QUERY_REFERER = 'https://takima.staging.deadlock.io';
diff --git a/deadlock-plugins/deadlock-extension/src/config.ts b/deadlock-plugins/deadlock-extension/src/config.ts
index a53b3ab5bba69c5e9d7ed0ef82f7662a8227933f..fcbe08addba35d99f5fd64632720c89235514ed1 100644
--- a/deadlock-plugins/deadlock-extension/src/config.ts
+++ b/deadlock-plugins/deadlock-extension/src/config.ts
@@ -5,3 +5,9 @@ export const KEYCLOAK_TOKEN_CREATE_URL =
 export const KEYCLOAK_USER_INFO_URL =
   'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo';
 export const REJECT_UNAUTHORIZED = false;
+export const ENABLE_AUTOMATIC_SAVE = true;
+export const ENABLE_RECORDER_HTTP_SERVER = false;
+export const RECORDER_HTTP_SERVER_PORT = 8751;
+export const RECORDER_HTTP_SERVER_URL = `http://localhost:${RECORDER_HTTP_SERVER_PORT}`;
+export const API_URL = 'https://api.dev.deadlock.io/';
+export const API_QUERY_REFERER = 'https://takima.dev.deadlock.io';
diff --git a/deadlock-plugins/deadlock-extension/src/core/api.service.ts b/deadlock-plugins/deadlock-extension/src/core/api.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b41170e7c48a64d0db59446afbc8ecdf47cc216f
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/core/api.service.ts
@@ -0,0 +1,122 @@
+import axios, { AxiosInstance } from 'axios';
+import { API_QUERY_REFERER, API_URL } from '../config';
+import { GiteaPublicProperties } from '../model/giteaPublicProperties.model';
+import { SshKeyPair } from '../model/sshKeyPair.model';
+import { User } from '../model/user.model';
+import Controller from './controller';
+import ExtensionStore from './extensionStore';
+import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection';
+
+export default class ApiService {
+  private axiosInstance: AxiosInstance;
+  constructor(
+    private keycloackConnection: KeycloakOAuth2DeviceFlowConnection,
+    private extensionStore: ExtensionStore,
+    private controller: Controller,
+  ) {
+    this.axiosInstance = axios.create({
+      baseURL: API_URL,
+      headers: {
+        'Content-Type': 'application/json',
+        referer: API_QUERY_REFERER,
+      },
+    });
+
+    this.initApiInterceptor();
+  }
+
+  initApiInterceptor() {
+    this.initRequestInterceptor();
+    this.initResponseInterceptor();
+  }
+
+  private initRequestInterceptor() {
+    this.axiosInstance.interceptors.request.use(
+      async (config) => {
+        const accessToken = await this.extensionStore.getAccessToken();
+        if (accessToken && config.headers) {
+          config.headers['authorization'] = `BEARER ${accessToken}`;
+        }
+        return config;
+      },
+      (error) => {
+        return Promise.reject(error);
+      },
+    );
+  }
+
+  private initResponseInterceptor() {
+    this.axiosInstance.interceptors.response.use(
+      (res) => {
+        return res;
+      },
+      async (err) => {
+        return await this.handleResponseError(err);
+      },
+    );
+  }
+
+  private async handleResponseError(err) {
+    const originalConfig = err.config;
+    if (err.response) {
+      // Access Token was expired
+      if (err.response.status === 401) {
+        if (!originalConfig._retry) {
+          originalConfig._retry = true;
+          return await this.onRetry(originalConfig);
+        } else if (originalConfig._retry) {
+          // IF REFRESH TOKEN NOT WORK, REQUEST NEW CONNECTION IN USER BROWSER
+          return await this.onInvalidRefreshToken(originalConfig);
+        }
+      }
+      if (err.response.status === 403 && err.response.data) {
+        return Promise.reject(err.response.data);
+      }
+    }
+    return Promise.reject(err);
+  }
+
+  private async onRetry(originalConfig) {
+    try {
+      const storedRefreshToken = await this.extensionStore.getRefreshToken();
+      const { accessToken, refreshToken } = await this.keycloackConnection.getToken({
+        refreshToken: storedRefreshToken,
+        openLink: Controller.openBrowserWithUrl,
+      });
+
+      await this.extensionStore.setAccessToken(accessToken);
+      await this.extensionStore.setRefreshToken(refreshToken);
+
+      this.axiosInstance.defaults.headers.common['authorization'] = `BEARER ${accessToken}`;
+      return this.axiosInstance(originalConfig);
+    } catch (_error) {
+      if (_error.response && _error.response.data) {
+        return Promise.reject(_error.response.data);
+      }
+      return await this.onInvalidRefreshToken(originalConfig);
+    }
+  }
+
+  private async onInvalidRefreshToken(originalConfig) {
+    try {
+      await this.controller.authenticate();
+      return this.axiosInstance(originalConfig);
+    } catch (_error) {
+      return Promise.reject(_error);
+    }
+  }
+
+  getGiteaPublicProperties(): Promise<GiteaPublicProperties> {
+    return this.axiosInstance.get<GiteaPublicProperties>(`gitea`).then((res) => res.data);
+  }
+
+  getUserSshKey(): Promise<SshKeyPair> {
+    return this.axiosInstance.put<SshKeyPair>(`users/gitea/keypair`).then((res) => res.data);
+  }
+
+  getUser(): Promise<User> {
+    return this.axiosInstance.get<User>(`auth`).then((res) => {
+      return res.data;
+    });
+  }
+}
diff --git a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts
index 9dcdc452f031924a31a33349fd1ce8566ffedee0..bcaea34d75703232e460fd717821db4245b80f54 100644
--- a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts
@@ -1,12 +1,8 @@
 import { commands } from 'vscode';
 import { Command } from '../theia/command';
 import Controller from './controller';
-import ExtensionStore from './extensionStore';
-
 export class CommandHandler {
-  private extensionStore: ExtensionStore;
   constructor(private controller: Controller) {
-    this.extensionStore = ExtensionStore.getInstance();
     this.initCommandHandler();
   }
 
diff --git a/deadlock-plugins/deadlock-extension/src/core/config.ts b/deadlock-plugins/deadlock-extension/src/core/config.ts
index 629d89ddb3183a72bfab6d8bb97bd6e15fc91049..c0849c9d760a422e78274cb749c924528cc57e31 100644
--- a/deadlock-plugins/deadlock-extension/src/core/config.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/config.ts
@@ -1,19 +1,23 @@
 import * as os from 'os';
 import * as path from 'path';
+import isDocker from 'is-docker';
 
 const homeDir = os.homedir();
 // if we are on container, means the directory will depend differently
-const onContainer = homeDir.includes('theia') || homeDir.includes('root');
+const onContainer = isDocker();
 
 const deadlockExtensionPath = path.join(homeDir, 'deadlock-extension');
 
+const deadlockConfigPath = path.join(homeDir, '.deadlock');
+export const userSshKeyFolderPath = path.join(deadlockConfigPath, '.ssh');
+
 export const PROJECT_SRC_PATH = onContainer ? '/project' : path.join(homeDir, 'deadlock-extension', '/project');
 
-export const PROJECT_THEIA_PATH = onContainer
-  ? path.join('/home/project')
+export const PROJECT_DEADLOCK_DESKTOP_PATH = onContainer
+  ? path.join('/home/deadlock/mission')
   : path.join(deadlockExtensionPath, 'project-theia');
 
-export const DOCS_PATH = path.join(path.join(onContainer ? '/home/theia' : deadlockExtensionPath), 'docs');
+export const DOCS_PATH = path.join(path.join(onContainer ? '/home/deadlock' : deadlockExtensionPath), 'docs');
 
 export const CONFIG_PATH = onContainer ? '/home/config/' : path.join(deadlockExtensionPath, 'config');
 
@@ -21,8 +25,8 @@ export const USER_CHALLENGE_PATH = path.join(CONFIG_PATH, 'user-challenge.json')
 
 export const BRIEFING_FILE_NAME = 'briefing.md';
 
-export const ENV_FILE_PATH = path.join(PROJECT_THEIA_PATH, '/.env');
+export const ENV_FILE_PATH = path.join(PROJECT_DEADLOCK_DESKTOP_PATH, '/.env');
 
 export const BASHRC_PATH = path.join(homeDir, '/.bashrc');
 
-export const SERVICES_PATHS_PATH = path.join(PROJECT_THEIA_PATH, '/paths.json');
+export const SERVICES_PATHS_PATH = path.join(PROJECT_DEADLOCK_DESKTOP_PATH, '/paths.json');
diff --git a/deadlock-plugins/deadlock-extension/src/core/controller.ts b/deadlock-plugins/deadlock-extension/src/core/controller.ts
index 7d7d3bb15fec7d1d56978bac11aa52d28b86716f..00d6a14d1ecc6a766f4dd6d4990317cb2d780b98 100644
--- a/deadlock-plugins/deadlock-extension/src/core/controller.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/controller.ts
@@ -1,11 +1,17 @@
 import * as vscode from 'vscode';
 import { KEYCLOAK_DEVICE_AUTH_URL, KEYCLOAK_TOKEN_CREATE_URL, KEYCLOAK_USER_INFO_URL } from '../config';
-import { OPEN_QUICK_SETUP_COMMAND } from '../theia/command';
+import { log } from '../recorder/utils';
 import BriefingView from '../view/briefingView';
 import QuickSetupView from '../view/quickSetupView';
 import { CHOOSE_MISSION_WORKDIR_COMMAND, CommandHandler, OPEN_URL_IN_BROWSER_COMMAND } from './commandHandler';
 import ExtensionStore from './extensionStore';
 import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection';
+import ApiService from './api.service';
+import { createSshKeyFiles, isSshKeyPairExist } from './sshKeyManager';
+import { GiteaPublicProperties } from '../model/giteaPublicProperties.model';
+import { User } from '../model/user.model';
+import { Mission } from './mission/mission';
+import { MissionDevContainer } from './mission/missionDevContainer';
 
 export default class Controller {
   public connection: KeycloakOAuth2DeviceFlowConnection;
@@ -13,6 +19,7 @@ export default class Controller {
   private briefingView: BriefingView;
   private quickSetupView: QuickSetupView;
   private extensionStore: ExtensionStore;
+  private apiService: ApiService;
 
   constructor(private context: vscode.ExtensionContext) {
     this.extensionStore = ExtensionStore.getInstance(context);
@@ -25,18 +32,30 @@ export default class Controller {
       KEYCLOAK_USER_INFO_URL,
     );
 
+    this.apiService = new ApiService(this.connection, this.extensionStore, this);
+
     this.init();
   }
+
   private async init() {
     const that = this;
     vscode.window.registerUriHandler({
       handleUri(uri: vscode.Uri) {
-        const queryParams: URLSearchParams = new URLSearchParams(uri.query);
-        const action: string | null = queryParams.get('action');
+        const queryParams = new URLSearchParams(uri.query);
+        const action = queryParams.get('action');
+        // TODO: Should we follow eslint no-case-declarations ?
+        const missionId = queryParams.get('missionId');
+        const missionVersion = queryParams.get('missionVersion');
+        log('Opening link', uri);
 
         switch (action) {
-          case 'open-challenge':
-            that.launchMission(queryParams.get('missionId'));
+          case 'open-mission':
+            if (!missionId || !missionVersion) {
+              vscode.window.showErrorMessage('Identifiant ou version de la mission incorrect');
+            } else {
+              that.launchMission(missionId, missionVersion);
+            }
+
             break;
 
           default:
@@ -45,9 +64,9 @@ export default class Controller {
       },
     });
 
-    const exensionStorage = ExtensionStore.getInstance();
-    this.quickSetupView.isAlreadyConnected = !!(await exensionStorage.getAccessToken());
+    this.quickSetupView.isAlreadyConnected = (await this.extensionStore.getAccessToken()) !== undefined;
   }
+
   async chooseMissionWorkdir() {
     const actualMissionWorkDir = this.extensionStore.getMissionWorkdir();
 
@@ -67,43 +86,57 @@ export default class Controller {
       this.extensionStore.setMissionWorkdir(folderUri[0].path);
     }
   }
+
   public async clear() {
-    const exensionStorage = ExtensionStore.getInstance();
-    await exensionStorage.clear();
+    await this.extensionStore.clear();
     this.quickSetupView.isAlreadyConnected = false;
   }
 
+  public async createSshKeyPairIfNotExist() {
+    if (isSshKeyPairExist()) return;
+    const { publicKey, privateKey } = await this.apiService.getUserSshKey();
+    await createSshKeyFiles(publicKey, privateKey);
+  }
+
   public async authenticate() {
-    // WARN generate a new device code every time student clicks on log in button. Should I keep it ?\
-    // The answer might be 'yes' because when the student is already authenticated, the log in button should be disabled.
     await this.connection.registerDevice();
     const tokens = await this.connection.getToken({ openLink: Controller.openBrowserWithUrl });
     await this.extensionStore.setAccessToken(tokens.accessToken);
     await this.extensionStore.setRefreshToken(tokens.refreshToken);
+    await this.createSshKeyPairIfNotExist();
     this.quickSetupView.isAlreadyConnected = true;
   }
+
   public static openBrowserWithUrl(url: string) {
     vscode.commands.executeCommand(OPEN_URL_IN_BROWSER_COMMAND.cmd, vscode.Uri.parse(url));
   }
 
-  public async launchMission(missionId: string | null) {
-    if (missionId) {
-      vscode.window.showInformationMessage(`vous lancez la mission ${missionId}`);
-      const hadMissionWorkdir = this.extensionStore.getMissionWorkdir() !== undefined;
-      if (!hadMissionWorkdir) {
-        await vscode.commands.executeCommand(CHOOSE_MISSION_WORKDIR_COMMAND.cmd);
-      }
-
-      const hadBeenConnected = (await this.extensionStore.getAccessToken()) !== undefined;
+  public async launchMission(missionId: string, missionVersion: string) {
+    vscode.window.showInformationMessage(`vous lancez la mission ${missionId}`);
+    const hadMissionWorkdir = this.extensionStore.getMissionWorkdir() !== undefined;
+    if (!hadMissionWorkdir) {
+      await vscode.commands.executeCommand(CHOOSE_MISSION_WORKDIR_COMMAND.cmd);
+    }
 
-      if (!hadBeenConnected) {
-        this.authenticate();
-        vscode.window.showInformationMessage('Nouvelle connexion validée');
-      } else {
-        vscode.window.showInformationMessage('Déjà connecté: session récupérée');
-      }
+    const hadBeenConnected = (await this.extensionStore.getAccessToken()) !== undefined;
 
-      vscode.commands.executeCommand(OPEN_QUICK_SETUP_COMMAND.cmd);
+    if (!hadBeenConnected) {
+      await this.authenticate();
+      vscode.window.showInformationMessage('Connexion validée');
     }
+
+    const mission = new Mission(missionId, missionVersion);
+
+    const missionsWorkdir = this.extensionStore.getMissionWorkdir() ?? '';
+    const user: User = await this.apiService.getUser();
+    const giteaPublicProperties: GiteaPublicProperties = await this.apiService.getGiteaPublicProperties();
+
+    const missionDevcontainer = new MissionDevContainer(missionsWorkdir, user, mission, giteaPublicProperties);
+
+    vscode.window.showInformationMessage(
+      'opening inside folder ' + this.extensionStore.getMissionWorkdir()! + '/' + missionId,
+    );
+
+    await missionDevcontainer.open();
   }
 }
diff --git a/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts
index 5d4497c98e99a9929c8e88368d2c8a445bb602cc..1bb67b4261b4e4b69d76ff489b538d8dc0c11c1d 100644
--- a/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts
@@ -16,7 +16,7 @@ export default class ExtensionStore {
 
   public async clear() {
     if (this.globalStorage.keys()) {
-      for (let key of this.globalStorage.keys()) {
+      for (const key of this.globalStorage.keys()) {
         this.globalStorage.update(key, undefined);
       }
     }
@@ -42,35 +42,35 @@ export default class ExtensionStore {
     window.showInformationMessage(`Nouveau dossier de stockage des missions: ${path}`);
   }
 
-  public async getAccessToken() {
+  public getAccessToken(): Thenable<string | undefined> {
     return this.readSecret(StoreKey.AccessTokenKey);
   }
 
-  public async getRefreshToken() {
+  public getRefreshToken(): Thenable<string | undefined> {
     return this.readSecret(StoreKey.RefreshTokenKey);
   }
 
-  public async setAccessToken(accessToken: string) {
+  public setAccessToken(accessToken: string): Thenable<void> {
     if (!accessToken) {
       log('Attempt to store undefined access token');
-      return;
+      return Promise.resolve();
     }
     return this.storeSecret(StoreKey.AccessTokenKey, accessToken);
   }
 
-  public async setRefreshToken(refreshToken: string) {
+  public setRefreshToken(refreshToken: string): Thenable<void> {
     if (!refreshToken) {
       log('Attempt to store undefined refresh token');
-      return;
+      return Promise.resolve();
     }
     return this.storeSecret(StoreKey.RefreshTokenKey, refreshToken);
   }
 
-  private async storeSecret(key: StoreKey, value: string) {
-    this.secretStorage.store(key, value);
+  private storeSecret(key: StoreKey, value: string): Thenable<void> {
+    return this.secretStorage.store(key, value);
   }
 
-  private async readSecret(key: StoreKey) {
+  private readSecret(key: StoreKey): Thenable<string | undefined> {
     return this.secretStorage.get(key);
   }
 }
diff --git a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts
index 9e739afc67856fa5f0f13e735acde4d5e2f4554a..3bed6fd3f7d48a2dfcfa785cbf38a84cc76af3d0 100644
--- a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts
@@ -1,5 +1,5 @@
 import simpleGit, { SimpleGit, SimpleGitOptions } from 'simple-git';
-import { error } from '../recorder/utils';
+import { error, log } from '../recorder/utils';
 import { PROJECT_SRC_PATH } from './config';
 import UserConfig from './userConfig';
 
@@ -7,7 +7,12 @@ const util = require('util');
 const exec = util.promisify(require('child_process').exec);
 
 const DEFAULT_REMOTE = 'origin';
-const DEFAULT_BRANCH = 'master';
+
+export enum Branch {
+  MASTER = 'master',
+  DEFAULT = MASTER,
+  LIVE = 'live',
+}
 
 export default class GitMission {
   private git: SimpleGit;
@@ -27,10 +32,10 @@ export default class GitMission {
       `eval "$(ssh-agent -s)" && ssh-keyscan -p ${this.userConfig.getGiteaSshPort()} -H ${this.userConfig.getGiteaHost()} >> ~/.ssh/known_hosts`,
     );
 
-    console.log(stdout);
+    log(stdout);
 
     if (err) {
-      console.error(stderr);
+      error(stderr);
       throw new Error(err);
     }
   }
@@ -41,12 +46,13 @@ export default class GitMission {
 
   async init() {
     try {
-      console.log('Setup ssh agent');
+      log('Setup ssh agent');
       await this.setupSshAgent();
 
-      console.log('Init Git mission..');
+      log('Init Git mission..');
 
       const remote = await this.readRemote();
+
       if (remote === DEFAULT_REMOTE) {
         return Promise.resolve(this);
       }
@@ -54,6 +60,7 @@ export default class GitMission {
       const remotePath = this.getRemotePath();
 
       await this.git.init();
+
       await this.git.addRemote(DEFAULT_REMOTE, remotePath);
       await this.git.addConfig('user.email', this.userConfig.getCurrentUserDetails().email, false, 'system');
       await this.git.addConfig(
@@ -87,20 +94,47 @@ export default class GitMission {
     return this.git.fetch(DEFAULT_REMOTE);
   }
 
-  pull() {
-    return this.git.pull(DEFAULT_REMOTE, DEFAULT_BRANCH, { '--rebase': 'true' });
+  pull(branch?: string) {
+    return this.git.pull(DEFAULT_REMOTE, branch ?? Branch.DEFAULT, { '--rebase': 'true' });
   }
 
   addAll() {
     return this.git.add('.');
   }
 
-  commit(message) {
-    return this.git.commit(message);
+  commit(message: string, options?: string[]) {
+    return this.git.commit(message, options ?? []);
   }
 
   push() {
-    return this.git.push(DEFAULT_REMOTE, DEFAULT_BRANCH);
+    return this.git.push(DEFAULT_REMOTE);
+  }
+
+  createLocalBranch(branch: string) {
+    return this.git.checkout(['-b', branch]);
+  }
+
+  createRemoteBranch(branch: string) {
+    return this.git.push(['-u', DEFAULT_REMOTE, branch]);
+  }
+
+  setUpstream(branch: string) {
+    return this.git.branch(['-u', DEFAULT_REMOTE, branch]);
+  }
+
+  createBranch(branch: string) {
+    const createBranchLocally = this.createLocalBranch(branch);
+    const createRemoteBranch = this.createRemoteBranch(branch);
+
+    return Promise.all([createBranchLocally, createRemoteBranch]);
+  }
+
+  checkout(branch: string) {
+    return this.git.checkout(branch);
+  }
+
+  merge(options?: string[]) {
+    return this.git.merge(options ?? []);
   }
 
   async isRemoteRepoExist() {
diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts
index 006d71388862f23244deef583bda1675242eb2e8..5797fbef288f9211edf3cf56472b0e474e8b790c 100644
--- a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts
@@ -27,14 +27,14 @@ export default class KeycloakOAuth2DeviceFlowConnectionTest {
       log(`click here: ${link}`);
     };
 
-    let tokens = await this.connection.getToken({ openLink: openLinkPlaceholder });
+    const tokens = await this.connection.getToken({ openLink: openLinkPlaceholder });
     log('tokens', tokens);
     if (!tokens?.refreshToken) {
       log("refresh token doesn't exist");
       return;
     }
 
-    let refreshedTokens = await this.connection.getToken({
+    const refreshedTokens = await this.connection.getToken({
       refreshToken: tokens.refreshToken,
       openLink: openLinkPlaceholder,
     });
diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts
index e0fbb38bf3c481e4ddafe1262b2d0b40c281981e..010a224eec573ac4d6f38d3d23430d616ed961c6 100644
--- a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts
@@ -65,9 +65,9 @@ export default class KeycloakOAuth2DeviceFlowConnection {
     }
   }
 
-  public async getToken(args: { refreshToken?: string; openLink: (link: string) => void }) {
+  public async getToken(args: { refreshToken?: string; openLink?: (link: string) => void }) {
     const { refreshToken, openLink } = args;
-    if (!!refreshToken) {
+    if (refreshToken !== undefined) {
       await this.createUserAuthentication({
         url: this.tokenUrl,
         body: (() => {
@@ -85,6 +85,7 @@ export default class KeycloakOAuth2DeviceFlowConnection {
       await this.registerDevice();
     }
     try {
+      if (!openLink) throw new Error('You neeed to provide a way to open a link for oauth device flow protocol');
       openLink(this.deviceAuthorizationRequestResponse.verification_uri_complete!);
       await this.createUserAuthentication({
         url: this.tokenUrl,
@@ -153,6 +154,7 @@ export default class KeycloakOAuth2DeviceFlowConnection {
         agent: new https.Agent({ rejectUnauthorized: REJECT_UNAUTHORIZED }),
       });
       userAuthenticationRequestResponseCode = userAuthenticationRequestResponse.status;
+      log(` Status ${userAuthenticationRequestResponseCode}`);
       switch (userAuthenticationRequestResponseCode) {
         case HttpStatusCode.BAD_REQUEST: {
           await this.onUserAuthenticationBadRequest(userAuthenticationRequestResponse);
diff --git a/deadlock-plugins/deadlock-extension/src/core/metadataProvider.ts b/deadlock-plugins/deadlock-extension/src/core/metadataProvider.ts
deleted file mode 100644
index a598545b60abeb4628fb4f5e15949b5dcd391b18..0000000000000000000000000000000000000000
--- a/deadlock-plugins/deadlock-extension/src/core/metadataProvider.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { exec, ExecException } from 'child_process';
-import * as fs from 'fs';
-import { userConfig } from '../extension';
-import { error as err, log } from '../recorder/utils';
-import { BASHRC_PATH, ENV_FILE_PATH } from './config';
-
-export default class MetadataProvider {
-  public static loadPathsToJson(filePath: string) {
-    const portToPath = userConfig.getPaths();
-    const serviceNameToPath = this.getServicePathFromPortPath(portToPath);
-    const jsonValue = Object.fromEntries(serviceNameToPath);
-    const fileContent = JSON.stringify(jsonValue, null, 4) + '\n';
-    fs.writeFileSync(filePath, fileContent, { flag: 'w+' });
-  }
-
-  public static loadPathsToEnvVariables(): void {
-    const portToPath = userConfig.getPaths();
-    const serviceNameToPath = this.getServicePathFromPortPath(portToPath);
-    let fileContent = '';
-    for (const [serviceName, servicePath] of serviceNameToPath.entries()) {
-      fileContent += `${serviceName}=${servicePath} \n`;
-    }
-    fs.writeFileSync(ENV_FILE_PATH, fileContent, { flag: 'w+' });
-    const bashrcAppendContent = `
-export $(cat ${ENV_FILE_PATH} | xargs -L 1)
-`;
-    fs.writeFileSync(BASHRC_PATH, bashrcAppendContent, { flag: 'a+' });
-    exec(`. ${BASHRC_PATH}`, execCallback);
-  }
-
-  /**
-   * two formats to handle: (key="front", value="3001") | (key="8080": value="HXW3fnKwUULrfKS1-cdb")\
-   * expected result: (key="front", value="localhost:3001") | (key="cdb", value="HXW3fnKwUULrfKS1-cdb")
-   *
-   */
-  private static getServicePathFromPortPath(portToPath: Map<number, string>): Map<string, string> {
-    const serviceToPath = new Map<string, string>();
-    for (const [port, path] of Object.entries(portToPath)) {
-      let key = '';
-      let value = '';
-      if (isNumeric(port)) {
-        key = path.split('-').slice(-1);
-        value = `${path}.${userConfig.getHost()}`;
-      } else {
-        key = port;
-        value = `localhost:${path}`;
-      }
-      serviceToPath.set(key, value);
-    }
-    return serviceToPath;
-  }
-}
-
-function isNumeric(val: string) {
-  return /^\d+$/.test(val);
-}
-
-function execCallback(error: ExecException | null, stdout: string, stderr: string) {
-  if (error) {
-    err(`error: ${error.message}`);
-    return;
-  }
-  if (stderr) {
-    err(`stderr: ${stderr}`);
-    return;
-  }
-  log(stdout);
-}
diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/devContainer.ts b/deadlock-plugins/deadlock-extension/src/core/mission/devContainer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..29db6bb3c01d7e6616e6f9141c55e5bdbf7c8948
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/core/mission/devContainer.ts
@@ -0,0 +1,44 @@
+export interface DockerfileSpecific {
+  image?: string;
+  dockerFile?: string;
+  context?: string;
+  'build.args'?: string[];
+  'build.target'?: string;
+  'build.cacheFrom'?: string;
+  containerEnv?: string;
+  containerUser?: string;
+  mounts?: string[];
+  workspaceMount?: string;
+  workspaceFolder?: string;
+  runArgs?: string[];
+}
+
+export interface Base {
+  name?: string;
+  forwardPorts?: string[];
+  portsAttributes?: string[];
+  otherPortsAttributes?: string[];
+  remoteEnv?: string;
+  remoteUser?: string;
+  updateRemoteUserUID?: string;
+  userEnvProbe?: string;
+  overrideCommand?: boolean;
+  features?: string[];
+  shutdownAction?: string;
+}
+
+export interface VSCodespecific {
+  extensions?: string[];
+  settings?: Record<string, unknown>;
+  devPort?: string;
+}
+
+export interface LifecycleScripts {
+  initializeCommand?: string;
+  onCreateCommand?: string;
+  updateContentCommand?: string;
+  postCreateCommand?: string;
+  postStartCommand?: string;
+  postAttachCommand?: string;
+  waitFor?: string;
+}
diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/mission.ts b/deadlock-plugins/deadlock-extension/src/core/mission/mission.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ba27109c96a09ddd2633e3ff21045b3b8f192da9
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/core/mission/mission.ts
@@ -0,0 +1,9 @@
+export class Mission {
+  readonly id: string;
+  readonly version: string;
+
+  constructor(id: string, version: string) {
+    this.id = id;
+    this.version = version;
+  }
+}
diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a8dc306c1de9a674287cc0974451379e8275a12e
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts
@@ -0,0 +1,113 @@
+import { userSshKeyFolderPath } from '../config';
+import { Base, DockerfileSpecific, LifecycleScripts, VSCodespecific } from './devContainer';
+import { existsSync } from 'fs';
+import { mkdir, writeFile } from 'fs/promises';
+import { Mission } from './mission';
+import { User, UserChallengeJson } from '../../model/user.model';
+import { GiteaPublicProperties } from '../../model/giteaPublicProperties.model';
+import { commands, Uri } from 'vscode';
+import assert = require('assert');
+
+const DOCKER_IMAGE_URL = 'registry.takima.io/deadlock/deadlock-challenges';
+
+export class MissionDevContainer {
+  private isInit = false;
+
+  private readonly dirs = {
+    missionWorkdir: `${this.missionsWorkdir}/${this.mission.id}`,
+    config: `${this.missionsWorkdir}/${this.mission.id}/.config`,
+    devcontainer: `${this.missionsWorkdir}/${this.mission.id}/.devcontainer`,
+    mounted: `${this.missionsWorkdir}/${this.mission.id}/mounted`,
+  };
+
+  constructor(
+    private readonly missionsWorkdir: string,
+    private readonly user: User,
+    private readonly mission: Mission,
+    private readonly giteaProperties: GiteaPublicProperties,
+  ) {}
+
+  async open() {
+    if (!this.isInit) {
+      await this.init();
+    }
+    assert(existsSync(this.dirs.missionWorkdir));
+    await commands.executeCommand('remote-containers.openFolder', Uri.file(this.dirs.missionWorkdir));
+  }
+
+  private async init() {
+    if (this.isInit) {
+      throw new Error(`${MissionDevContainer.constructor.name} Already initialized`);
+    }
+    this.isInit = true;
+    await this.createDirectories(...Object.values(this.dirs));
+    await this.createDevContainerFile();
+    await this.createUserChallengeJsonFile();
+  }
+
+  private createUserChallengeJsonFile() {
+    return writeFile(
+      `${this.dirs.config}/user-challenge.json`,
+      (() => {
+        const userChallengeJson: UserChallengeJson = {
+          giteaHost: this.giteaProperties.sshHost,
+          giteaSshPort: this.giteaProperties.sshPort,
+          username: this.user.id.split('-').join(''),
+          email: `${this.user.id.split('-').join('')}@deadlock.io`,
+          missionId: this.mission.id,
+          remoteGitUsername: this.user.id.split('-').join(''),
+          currentUserDetails: this.user.details,
+          remoteUserDetails: this.user.details,
+        };
+        return JSON.stringify(userChallengeJson, null, 2);
+      })(),
+    );
+  }
+
+  private createDevContainerFile(options?: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts>) {
+    const remoteUserHomeDir = '/home/deadlock';
+    const remoteMissionDir = `${remoteUserHomeDir}/mission/`;
+    const remoteGiteaWorkDir = `/workdir`;
+    const hostMissionDevcontainerFileDir = `${this.dirs.devcontainer}/devcontainer.json`;
+
+    const image = `${DOCKER_IMAGE_URL}/${this.mission.id}:${this.mission.version}`;
+
+    return writeFile(
+      hostMissionDevcontainerFileDir,
+      (() => {
+        const devcontainer: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts> = {
+          name: `deadlock-${this.mission.id}`,
+          image,
+          extensions: ['Deadlock.deadlock-coding'],
+          remoteUser: 'deadlock',
+          mounts: [
+            `source=${userSshKeyFolderPath},target=/tmp/.ssh,type=bind,consistency=cached,readonly`,
+            `source=${this.dirs.config},target=/home/config/,type=bind,consistency=cached,readonly`,
+            'source=/etc/hosts,target=/etc/hosts,type=bind,consistency=cached,readonly',
+          ],
+          userEnvProbe: 'interactiveShell',
+          settings: {
+            'terminal.integrated.defaultProfile.linux': 'bash',
+            'terminal.integrated.profiles.linux': {
+              bash: {
+                path: '/bin/bash',
+              },
+            },
+          },
+          overrideCommand: false,
+          shutdownAction: 'stopContainer',
+          workspaceMount: `source=${this.dirs.mounted},target=${remoteMissionDir},type=bind`,
+          workspaceFolder: `${remoteMissionDir}`,
+          onCreateCommand: `cp -R ${remoteGiteaWorkDir}/* ${remoteMissionDir}`,
+          runArgs: ['--privileged'],
+          ...options,
+        };
+        return JSON.stringify(devcontainer, null, 2);
+      })(),
+    );
+  }
+
+  private createDirectories(...directoryPaths: string[]) {
+    return Promise.all(directoryPaths.map((directoryPath) => mkdir(directoryPath, { recursive: true })));
+  }
+}
diff --git a/deadlock-plugins/deadlock-extension/src/core/sshKeyManager.ts b/deadlock-plugins/deadlock-extension/src/core/sshKeyManager.ts
new file mode 100644
index 0000000000000000000000000000000000000000..94d37e732cb725b21a9faf2c0213c25584e769ba
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/core/sshKeyManager.ts
@@ -0,0 +1,31 @@
+import * as fs from 'fs';
+import { userSshKeyFolderPath } from './config';
+
+export function isSshKeyPairExist(): boolean {
+  return isPrivateKeyExist() && isPublicKeyExist();
+}
+
+function isPublicKeyExist(): boolean {
+  return fs.existsSync(`${userSshKeyFolderPath}/id_rsa.pub`);
+}
+
+function isPrivateKeyExist(): boolean {
+  return fs.existsSync(`${userSshKeyFolderPath}/id_rsa`);
+}
+
+export async function createSshKeyFiles(publicKey: string, privateKey: string) {
+  await createSshKeyFolderIfNotExist(userSshKeyFolderPath);
+  await fs.promises.writeFile(`${userSshKeyFolderPath}/id_rsa.pub`, publicKey);
+
+  await fs.promises.writeFile(`${userSshKeyFolderPath}/id_rsa`, privateKey, { mode: 0o600 });
+}
+
+async function createSshKeyFolderIfNotExist(sshKeyFolderPath) {
+  if (!isSshKeyFolderExist(sshKeyFolderPath)) {
+    await fs.promises.mkdir(sshKeyFolderPath, { recursive: true });
+  }
+}
+
+export function isSshKeyFolderExist(sshKeyFolderPath: string) {
+  return fs.existsSync(sshKeyFolderPath);
+}
diff --git a/deadlock-plugins/deadlock-extension/src/core/userConfig.ts b/deadlock-plugins/deadlock-extension/src/core/userConfig.ts
index 46295519cf5a44668fabe677467787ecbfd7276e..d881fb9638bfcc8043cac525f37bcaa935062b6b 100644
--- a/deadlock-plugins/deadlock-extension/src/core/userConfig.ts
+++ b/deadlock-plugins/deadlock-extension/src/core/userConfig.ts
@@ -14,16 +14,9 @@
  * "missionId":"code_persist_cdb_crud"
  * }
  */
-
+import { UserDetails } from '../model/user.model';
 import { error } from '../recorder/utils';
 
-export interface UserDetails {
-  firstName: string;
-  lastName: string;
-  avatarUrl: string;
-  email: string;
-}
-
 export default abstract class UserConfig {
   private userConfigJson: any | undefined;
 
diff --git a/deadlock-plugins/deadlock-extension/src/customTypings/HttpStatusCode.ts b/deadlock-plugins/deadlock-extension/src/customTypings/HttpStatusCode.ts
index e5bb61ccb9a971188808ff21d9693ae63679e851..8c7d46c65ef2f0eafad1b8f58c13de46a500ee8b 100644
--- a/deadlock-plugins/deadlock-extension/src/customTypings/HttpStatusCode.ts
+++ b/deadlock-plugins/deadlock-extension/src/customTypings/HttpStatusCode.ts
@@ -158,7 +158,7 @@ export enum HttpStatusCode {
 
   /**
    * Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet
-   * been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the
+   * been provided. The response must include a WWW-Authenticate header field containing a mission applicable to the
    * requested resource. See Basic access authentication and Digest access authentication. 401 semantically means
    * "unauthenticated",i.e. the user does not have the necessary credentials.
    */
diff --git a/deadlock-plugins/deadlock-extension/src/extension.ts b/deadlock-plugins/deadlock-extension/src/extension.ts
index 506ad15ae186c4a443ddda1651c5a02ff2cb1bce..b025f980911c8ad90d924c388f4821609a9a8469 100644
--- a/deadlock-plugins/deadlock-extension/src/extension.ts
+++ b/deadlock-plugins/deadlock-extension/src/extension.ts
@@ -1,7 +1,5 @@
 import * as vscode from 'vscode';
-import { SERVICES_PATHS_PATH } from './core/config';
 import Controller from './core/controller';
-import MetadataProvider from './core/metadataProvider';
 import { error } from './recorder/utils';
 import { DepNodeProvider } from './theia/deadlockPanel';
 import UserConfigTheia from './theia/userConfigTheia';
@@ -11,7 +9,7 @@ export const userConfig = new UserConfigTheia();
 export async function activate(context: vscode.ExtensionContext) {
   vscode.window.showInformationMessage('Bienvenue sur Deadlock!');
 
-  const controller = new Controller(context);
+  new Controller(context);
 
   const workspaceFolders = vscode.workspace.workspaceFolders?.toString() ?? '';
   if (!workspaceFolders) vscode.window.showInformationMessage('Pas de répertoires ouverts');
@@ -23,7 +21,4 @@ export async function activate(context: vscode.ExtensionContext) {
   } catch (e) {
     error('Cannot init userConfig');
   }
-
-  MetadataProvider.loadPathsToEnvVariables();
-  MetadataProvider.loadPathsToJson(`${SERVICES_PATHS_PATH}`);
 }
diff --git a/deadlock-plugins/deadlock-extension/src/model/giteaPublicProperties.model.ts b/deadlock-plugins/deadlock-extension/src/model/giteaPublicProperties.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5c10aba3fd8e3a24e20ae78b992e23e06a43b29b
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/model/giteaPublicProperties.model.ts
@@ -0,0 +1,6 @@
+export interface GiteaPublicProperties {
+  apiHost: string;
+  sshHost: string;
+  port: number;
+  sshPort: number;
+}
diff --git a/deadlock-plugins/deadlock-extension/src/model/sshKeyPair.model.ts b/deadlock-plugins/deadlock-extension/src/model/sshKeyPair.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4e1868d587295b566eca654b3aa06a168e971345
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/model/sshKeyPair.model.ts
@@ -0,0 +1,4 @@
+export interface SshKeyPair {
+  privateKey: string;
+  publicKey: string;
+}
diff --git a/deadlock-plugins/deadlock-extension/src/model/user.model.ts b/deadlock-plugins/deadlock-extension/src/model/user.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7744bdc8f081d3c950926eb76932c3dc6078225b
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/model/user.model.ts
@@ -0,0 +1,37 @@
+import { GiteaPublicProperties } from './giteaPublicProperties.model';
+
+export interface User {
+  id: string;
+  details: UserDetails;
+}
+
+export interface UserDetails {
+  firstName: string;
+  lastName: string;
+  organization: string;
+  email: string;
+  login: string;
+  roles: string[];
+  avatarUrl: string;
+}
+
+export interface UserChallengeJson {
+  giteaHost: string;
+  giteaSshPort: number;
+  username: string;
+  email: string;
+  missionId: string;
+  remoteGitUsername: string;
+  currentUserDetails: UserDetails;
+  remoteUserDetails: UserDetails;
+}
+
+export interface UserChallengeJson2 {
+  gitea: Pick<GiteaPublicProperties, 'sshPort' | 'sshHost'>;
+  username: string;
+  email: string;
+  missionId: string;
+  remoteGitUsername: string;
+  currentUserDetails: UserDetails;
+  remoteUserDetails: UserDetails;
+}
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts b/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts
index 17865f4da95b95c0572a67cbb59456bb0fb82657..1a68a0b8ea208688101e267ae24b329a31885af6 100644
--- a/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts
+++ b/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts
@@ -1,7 +1,7 @@
 import GitMission from '../core/gitMission';
-import { error, commitAndPushCode, CommitFrom, log } from './utils';
-const async = require('async');
-const fs = require('fs');
+import { CommitFrom, error, updateRemote } from './utils';
+import * as async from 'async';
+import * as fs from 'fs';
 
 class Command {
   public still: boolean;
@@ -33,7 +33,7 @@ export default class CommandRecorder {
     if (!this.commandsInProgress.has(pid)) {
       this.commandsInProgress.set(pid, new Command(pid, command));
       try {
-        this.queue.push(async () => await commitAndPushCode(this.gitMission, CommitFrom.Run));
+        this.queue.push(async () => await updateRemote(this.gitMission, CommitFrom.Run));
       } catch (e) {
         console.error('Cannot send user code to git');
         console.error(e);
@@ -47,7 +47,7 @@ export default class CommandRecorder {
     let lastLineIndexWatched = 0;
     setInterval(() => {
       try {
-        const trace = fs.readFileSync('/home/theia/.bash_history', 'utf8');
+        const trace = fs.readFileSync('/home/deadlock/.bash_history', 'utf8');
         const lines = trace.split(/\r?\n/);
 
         this.commandsInProgress.forEach((command) => (command.still = false));
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/index.ts b/deadlock-plugins/deadlock-extension/src/recorder/index.ts
index 51f4a3a41cd3a2804c1ac81a2e2b5f5c15efbb72..0927ecf4f9af934c3d3ce1b92339570c9d0abaef 100644
--- a/deadlock-plugins/deadlock-extension/src/recorder/index.ts
+++ b/deadlock-plugins/deadlock-extension/src/recorder/index.ts
@@ -1,19 +1,24 @@
+import { Branch } from '../core/gitMission';
+import { ENABLE_AUTOMATIC_SAVE } from '../config';
 import CommandRecorder from './command-recorder';
 import GitMission from '../core/gitMission';
 import UserConfigNode from './userConfigNode';
-import { PROJECT_SRC_PATH, PROJECT_THEIA_PATH } from '../core/config';
-import { copyProjectSources, clearFilesExceptGit, log, error, renameTempToUserGitFiles } from './utils';
+import { PROJECT_DEADLOCK_DESKTOP_PATH, PROJECT_SRC_PATH } from '../core/config';
+import { clearFilesExceptGit, copyProjectSources, error, log, renameTempToUserGitFiles } from './utils';
 import UserConfig from '../core/userConfig';
+import HttpServer from './services/http-server';
+import { ENABLE_RECORDER_HTTP_SERVER } from '../config';
+import AutomaticSave from './services/automatic-save';
 
 export default class Recorder {
   async setupProject(userConfig: UserConfig, gitMission?: GitMission) {
     log('Setup user project..');
 
     if (!userConfig.isProfessor()) {
-      await copyProjectSources(PROJECT_SRC_PATH, PROJECT_THEIA_PATH, ['.git/']);
+      await copyProjectSources(PROJECT_SRC_PATH, PROJECT_DEADLOCK_DESKTOP_PATH, ['.git/']);
 
       if (gitMission) {
-        renameTempToUserGitFiles(PROJECT_THEIA_PATH, gitMission.author);
+        renameTempToUserGitFiles(PROJECT_DEADLOCK_DESKTOP_PATH, gitMission.author);
 
         log('Starting CommandRecorder..');
         new CommandRecorder(gitMission).run();
@@ -21,13 +26,14 @@ export default class Recorder {
         error('Cannot start command recorder, gitMission not found');
       }
     } else {
-      await copyProjectSources(PROJECT_SRC_PATH, PROJECT_THEIA_PATH);
+      await copyProjectSources(PROJECT_SRC_PATH, PROJECT_DEADLOCK_DESKTOP_PATH);
     }
   }
 
   async setupFromRemoteRepo(gitMission: GitMission) {
     log('Check if remote repo exist');
     const isRemoteRepoExist = await gitMission.isRemoteRepoExist();
+
     if (isRemoteRepoExist) {
       // rm all except git directory pull remote code and setup
       log('Cleaning files to pull repo');
@@ -35,7 +41,14 @@ export default class Recorder {
       await clearFilesExceptGit(PROJECT_SRC_PATH);
 
       log('Pulling user repo');
-      await gitMission.pull();
+
+      await gitMission.fetch();
+      await gitMission.checkout(Branch.MASTER);
+      await gitMission.checkout(Branch.LIVE);
+    } else {
+      await gitMission.commit('initial commit', ['--allow-empty']);
+      await gitMission.createRemoteBranch(Branch.DEFAULT);
+      await gitMission.createBranch(Branch.LIVE);
     }
   }
 
@@ -49,6 +62,7 @@ export default class Recorder {
       await userConfig.init();
       log('Init GitMission');
       gitMission = await new GitMission(userConfig).init();
+
       await this.setupFromRemoteRepo(gitMission);
     } catch (e) {
       error('Cannot setup user repo.');
@@ -60,6 +74,20 @@ export default class Recorder {
       error('Error while setup project sources');
       error(e);
     }
+
+    try {
+      if (ENABLE_AUTOMATIC_SAVE) new AutomaticSave(PROJECT_DEADLOCK_DESKTOP_PATH, gitMission);
+    } catch (e) {
+      error('Error while setup automatic save');
+      error(e);
+    }
+
+    try {
+      if (ENABLE_RECORDER_HTTP_SERVER) new HttpServer(gitMission);
+    } catch (e) {
+      error('Error while setup recorder http server');
+      error(e);
+    }
   }
 }
 
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/package-lock.json b/deadlock-plugins/deadlock-extension/src/recorder/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..851d67cb716f929309c6cc858c7b8b1f5dc3c274
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/recorder/package-lock.json
@@ -0,0 +1,1456 @@
+{
+  "name": "deadlock-recorder",
+  "version": "1.0.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "deadlock-recorder",
+      "version": "1.0.0",
+      "license": "MIT",
+      "dependencies": {
+        "chokidar": "^3.5.3",
+        "express": "^4.18.0"
+      },
+      "devDependencies": {
+        "@types/express": "^4.17.13"
+      }
+    },
+    "node_modules/@types/body-parser": {
+      "version": "1.19.2",
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
+      "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
+      "dev": true,
+      "dependencies": {
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/connect": {
+      "version": "3.4.35",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+      "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/express": {
+      "version": "4.17.13",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
+      "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
+      "dev": true,
+      "dependencies": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "^4.17.18",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "node_modules/@types/express-serve-static-core": {
+      "version": "4.17.28",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
+      "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
+    "node_modules/@types/mime": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+      "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
+      "dev": true
+    },
+    "node_modules/@types/node": {
+      "version": "17.0.29",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz",
+      "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==",
+      "dev": true
+    },
+    "node_modules/@types/qs": {
+      "version": "6.9.7",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+      "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+      "dev": true
+    },
+    "node_modules/@types/range-parser": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+      "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+      "dev": true
+    },
+    "node_modules/@types/serve-static": {
+      "version": "1.13.10",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
+      "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/mime": "^1",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/accepts": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+      "dependencies": {
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/body-parser": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
+      "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==",
+      "dependencies": {
+        "bytes": "3.1.2",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "on-finished": "2.4.1",
+        "qs": "6.10.3",
+        "raw-body": "2.5.1",
+        "type-is": "~1.6.18",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "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"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/content-disposition": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+      "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+      "dependencies": {
+        "safe-buffer": "5.2.1"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/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==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+    },
+    "node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/destroy": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
+    "node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+    },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/express": {
+      "version": "4.18.0",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.18.0.tgz",
+      "integrity": "sha512-EJEXxiTQJS3lIPrU1AE2vRuT7X7E+0KBbpm5GSoK524yl0K8X+er8zS2P14E64eqsVNoWbMCT7MpmQ+ErAhgRg==",
+      "dependencies": {
+        "accepts": "~1.3.8",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.20.0",
+        "content-disposition": "0.5.4",
+        "content-type": "~1.0.4",
+        "cookie": "0.5.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "1.2.0",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.7",
+        "qs": "6.10.3",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.2.1",
+        "send": "0.18.0",
+        "serve-static": "1.15.0",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/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==",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/finalhandler": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+      "dependencies": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "statuses": "2.0.1",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/http-errors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+      "dependencies": {
+        "depd": "2.0.0",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "toidentifier": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/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==",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/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==",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+    },
+    "node_modules/methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+    },
+    "node_modules/negotiator": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
+      "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/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="
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "dependencies": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.10.3",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+      "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/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==",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+      "dependencies": {
+        "bytes": "3.1.2",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/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==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "node_modules/send": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+      "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+      "dependencies": {
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "mime": "1.6.0",
+        "ms": "2.1.3",
+        "on-finished": "2.4.1",
+        "range-parser": "~1.2.1",
+        "statuses": "2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/send/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+    },
+    "node_modules/serve-static": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+      "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+      "dependencies": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.18.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+    },
+    "node_modules/side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/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==",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "dependencies": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    }
+  },
+  "dependencies": {
+    "@types/body-parser": {
+      "version": "1.19.2",
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
+      "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
+      "dev": true,
+      "requires": {
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
+    "@types/connect": {
+      "version": "3.4.35",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+      "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/express": {
+      "version": "4.17.13",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
+      "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
+      "dev": true,
+      "requires": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "^4.17.18",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "@types/express-serve-static-core": {
+      "version": "4.17.28",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
+      "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
+    "@types/mime": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+      "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
+      "dev": true
+    },
+    "@types/node": {
+      "version": "17.0.29",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz",
+      "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==",
+      "dev": true
+    },
+    "@types/qs": {
+      "version": "6.9.7",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+      "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+      "dev": true
+    },
+    "@types/range-parser": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+      "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+      "dev": true
+    },
+    "@types/serve-static": {
+      "version": "1.13.10",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
+      "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
+      "dev": true,
+      "requires": {
+        "@types/mime": "^1",
+        "@types/node": "*"
+      }
+    },
+    "accepts": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+      "requires": {
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
+      }
+    },
+    "anymatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "requires": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      }
+    },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+    },
+    "binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
+    },
+    "body-parser": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
+      "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==",
+      "requires": {
+        "bytes": "3.1.2",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "on-finished": "2.4.1",
+        "qs": "6.10.3",
+        "raw-body": "2.5.1",
+        "type-is": "~1.6.18",
+        "unpipe": "1.0.0"
+      }
+    },
+    "braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "requires": {
+        "fill-range": "^7.0.1"
+      }
+    },
+    "bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+    },
+    "call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "requires": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      }
+    },
+    "chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "requires": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "fsevents": "~2.3.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"
+      }
+    },
+    "content-disposition": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+      "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+      "requires": {
+        "safe-buffer": "5.2.1"
+      }
+    },
+    "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=="
+    },
+    "cookie": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+    },
+    "destroy": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+    },
+    "express": {
+      "version": "4.18.0",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.18.0.tgz",
+      "integrity": "sha512-EJEXxiTQJS3lIPrU1AE2vRuT7X7E+0KBbpm5GSoK524yl0K8X+er8zS2P14E64eqsVNoWbMCT7MpmQ+ErAhgRg==",
+      "requires": {
+        "accepts": "~1.3.8",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.20.0",
+        "content-disposition": "0.5.4",
+        "content-type": "~1.0.4",
+        "cookie": "0.5.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "1.2.0",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.7",
+        "qs": "6.10.3",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.2.1",
+        "send": "0.18.0",
+        "serve-static": "1.15.0",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      }
+    },
+    "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==",
+      "requires": {
+        "to-regex-range": "^5.0.1"
+      }
+    },
+    "finalhandler": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "statuses": "2.0.1",
+        "unpipe": "~1.0.0"
+      }
+    },
+    "forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+    },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+    },
+    "fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "optional": true
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "get-intrinsic": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+      "requires": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.1"
+      }
+    },
+    "glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "requires": {
+        "is-glob": "^4.0.1"
+      }
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+    },
+    "http-errors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+      "requires": {
+        "depd": "2.0.0",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "toidentifier": "1.0.1"
+      }
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "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=="
+    },
+    "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==",
+      "requires": {
+        "binary-extensions": "^2.0.0"
+      }
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+    },
+    "is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+    },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+    },
+    "mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+    },
+    "mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+    },
+    "mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "requires": {
+        "mime-db": "1.52.0"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+    },
+    "negotiator": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+    },
+    "normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+    },
+    "object-inspect": {
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
+      "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="
+    },
+    "on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+    },
+    "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="
+    },
+    "picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
+    },
+    "proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "requires": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      }
+    },
+    "qs": {
+      "version": "6.10.3",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+      "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+      "requires": {
+        "side-channel": "^1.0.4"
+      }
+    },
+    "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=="
+    },
+    "raw-body": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+      "requires": {
+        "bytes": "3.1.2",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      }
+    },
+    "readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "requires": {
+        "picomatch": "^2.2.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=="
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "send": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+      "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "mime": "1.6.0",
+        "ms": "2.1.3",
+        "on-finished": "2.4.1",
+        "range-parser": "~1.2.1",
+        "statuses": "2.0.1"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+      "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+      "requires": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.18.0"
+      }
+    },
+    "setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+    },
+    "side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "requires": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      }
+    },
+    "statuses": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+    },
+    "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==",
+      "requires": {
+        "is-number": "^7.0.0"
+      }
+    },
+    "toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+    },
+    "type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      }
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+    },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+    },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+    }
+  }
+}
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/package.json b/deadlock-plugins/deadlock-extension/src/recorder/package.json
index 3e8d60d9f770b499340fd375b4a7f628120e272e..bb63dc16d2dd366d4d5ac941c1b8c0a1c20df485 100644
--- a/deadlock-plugins/deadlock-extension/src/recorder/package.json
+++ b/deadlock-plugins/deadlock-extension/src/recorder/package.json
@@ -9,6 +9,10 @@
   "author": "",
   "license": "MIT",
   "dependencies": {
-    "deadlock-coding": "^0.0.1"
+    "chokidar": "^3.5.3",
+    "express": "^4.18.0"
+  },
+  "devDependencies": {
+    "@types/express": "^4.17.13"
   }
 }
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts b/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts
deleted file mode 100644
index e3154055e67b1b1a0d13521cc58a7c7891aac31e..0000000000000000000000000000000000000000
--- a/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import UserConfigNode from './userConfigNode';
-import GitMission from '../core/gitMission';
-import { PROJECT_SRC_PATH, PROJECT_THEIA_PATH } from '../core/config';
-
-import { log, error, commitAndPushCode, CommitFrom } from './utils';
-const util = require('util');
-const exec = util.promisify(require('child_process').exec);
-
-async function containsDiff() {
-  try {
-    // https://man7.org/linux/man-pages/man1/diff.1.html
-    // Exit status is 0 if inputs are the same, 1 if different, 2 if trouble.
-    await exec(`diff -qr ${PROJECT_SRC_PATH} ${PROJECT_THEIA_PATH}`);
-    // When status code is 0 exec does not fail
-  } catch (result) {
-    // when status code is > 0
-    if (result.code === 1) {
-      const stdout = result.stdout;
-      if (stdout.indexOf('Files ') !== -1 || stdout.indexOf('Only in /home/project/') !== -1) {
-        // if user created new file or added a directory
-        return true;
-      }
-    } else {
-      // print error
-      error(result.stderr);
-    }
-  }
-  return false;
-}
-
-(async () => {
-  try {
-    log('Container will die');
-
-    const userConfig = new UserConfigNode();
-    await userConfig.init();
-
-    if (!userConfig.isProfessor()) {
-      log('Save user code..');
-      const gitMission = await new GitMission(userConfig).init();
-      if (await containsDiff()) {
-        await commitAndPushCode(gitMission, CommitFrom.Auto);
-      }
-    }
-  } catch (e) {
-    error('Cannot push user code at the end..');
-    error(e);
-  }
-})();
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts b/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts
new file mode 100644
index 0000000000000000000000000000000000000000..154cc0ae4e829df391d8c210acd99d8f7bf75927
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts
@@ -0,0 +1,17 @@
+import { CommitFrom, getIgnorePatternFromIgnoreFile } from '../utils';
+import FileWatcher from './file-watcher';
+import { updateRemote } from '../utils';
+import GitMission from '../../core/gitMission';
+
+export default class AutomaticSave {
+  constructor(private folderToWatch: string, private gitMission: GitMission) {
+    this.setupAutomaticSave();
+  }
+
+  async setupAutomaticSave() {
+    const ignoreFilePatterns = await getIgnorePatternFromIgnoreFile('/deadlock/.gitignore');
+    new FileWatcher(this.folderToWatch, ['**/*'], ignoreFilePatterns, () => {
+      updateRemote(this.gitMission, CommitFrom.Auto);
+    });
+  }
+}
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/services/file-watcher.ts b/deadlock-plugins/deadlock-extension/src/recorder/services/file-watcher.ts
new file mode 100644
index 0000000000000000000000000000000000000000..133048b84824e25cb69b094e29764a4f24a71ff5
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/recorder/services/file-watcher.ts
@@ -0,0 +1,21 @@
+import * as chokidar from 'chokidar';
+
+export default class FileWatcher {
+  constructor(
+    private folderToWatch: string,
+    private watchFilePatterns: string[],
+    private ignoreFilePatterns: string[],
+    private onFilesChangeAction: () => void,
+  ) {
+    this.setupWatcher();
+  }
+
+  setupWatcher() {
+    const watcher = chokidar.watch(this.watchFilePatterns, {
+      cwd: this.folderToWatch,
+      ignored: this.ignoreFilePatterns,
+      ignoreInitial: true,
+    });
+    watcher.on('change', this.onFilesChangeAction);
+  }
+}
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/services/http-server.ts b/deadlock-plugins/deadlock-extension/src/recorder/services/http-server.ts
new file mode 100644
index 0000000000000000000000000000000000000000..53cdd2a6e3159c1ead4289360489d631c47cb372
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/recorder/services/http-server.ts
@@ -0,0 +1,38 @@
+import GitMission from '../../core/gitMission';
+import { Express } from 'express';
+import { CommitFrom, log, updateRemote } from '../utils';
+import { RECORDER_HTTP_SERVER_PORT } from '../../config';
+
+const express = require('express');
+export default class HttpServer {
+  app: Express;
+
+  constructor(private gitMission: GitMission) {
+    this.app = express();
+
+    this.setupSaveCodeEndpoints();
+
+    this.listen();
+  }
+
+  setupSaveCodeEndpoints() {
+    this.app.post('/save', async (req, res) => {
+      try {
+        await updateRemote(this.gitMission, CommitFrom.HttpServer);
+        res.status(200).json({
+          message: 'Commit & push done.',
+        });
+      } catch (error) {
+        res.status(400).json({
+          error,
+        });
+      }
+    });
+  }
+
+  listen() {
+    this.app.listen(RECORDER_HTTP_SERVER_PORT, () => {
+      log(`Http server listen on port ${RECORDER_HTTP_SERVER_PORT}`);
+    });
+  }
+}
diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils.ts
index cc271f3f93a3efba58d1b43ba020581c0f1f417e..1aa9fbb58d299f4e3bc0b2da0fa3b4e23ee5ce03 100644
--- a/deadlock-plugins/deadlock-extension/src/recorder/utils.ts
+++ b/deadlock-plugins/deadlock-extension/src/recorder/utils.ts
@@ -1,8 +1,9 @@
+import { Branch } from './../core/gitMission';
 import GitMission from '../core/gitMission';
-import { PROJECT_SRC_PATH, PROJECT_THEIA_PATH } from '../core/config';
+import { PROJECT_DEADLOCK_DESKTOP_PATH, PROJECT_SRC_PATH } from '../core/config';
 import { format } from 'date-fns';
 import { execSync } from 'child_process';
-import { existsSync, renameSync, copyFileSync, PathLike } from 'fs';
+import { copyFileSync, existsSync, PathLike, renameSync } from 'fs';
 
 const util = require('util');
 const unlink = util.promisify(require('fs').unlink);
@@ -11,7 +12,7 @@ const fs = require('fs');
 const readdirSync = require('fs').readdirSync;
 const Path = require('path');
 
-const PREFIX = '[DEADLOCK-RECORDER]';
+const PREFIX = '[55-RECORDER]';
 
 export const log = (message: any, ...args: any[]) => {
   if (args) {
@@ -29,9 +30,15 @@ export const error = (message: any, ...args: any[]) => {
   }
 };
 
-export async function copyProjectSources(srcPath: string, theiaPath: string, excludes: Array<string> = []) {
+export async function copyProjectSources(
+  srcPath: string,
+  userMissionWorkdirPath: string,
+  excludes: Array<string> = [],
+) {
   const excludeCmd = excludes.map((current) => `--exclude ${current}`).join(' ');
-  return exec(`rsync -a ${srcPath}/ ${theiaPath} ${excludeCmd} && chown -R theia:theia /home/project`);
+  return exec(
+    `rsync -a ${srcPath}/ ${userMissionWorkdirPath} ${excludeCmd} && chown -R deadlock:deadlock /home/deadlock`,
+  );
 }
 
 export async function pathContainsFiles(path: string) {
@@ -104,22 +111,29 @@ function copyGitUserFiles(srcPath: string, destPath: string, userId: string) {
 export enum CommitFrom {
   Run = 'Run',
   Auto = 'Auto',
+  HttpServer = 'HttpServer',
 }
 
-export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom) {
+export async function updateRemote(gitMission: GitMission, from: CommitFrom) {
+  if (from === CommitFrom.Auto) commitAndPushCode(gitMission);
+  if (from === CommitFrom.Run) mergeMaster(gitMission);
+}
+
+async function commitAndPushCode(gitMission: GitMission) {
   try {
-    log('Commit & push');
+    log('Doing Commit & push');
     await clearFilesExceptGit(PROJECT_SRC_PATH);
 
-    copyGitUserFiles(PROJECT_THEIA_PATH, PROJECT_SRC_PATH, gitMission.author);
+    copyGitUserFiles(PROJECT_DEADLOCK_DESKTOP_PATH, PROJECT_SRC_PATH, gitMission.author);
     execSync(
-      `rsync -r --exclude .git --exclude npm --exclude target ${PROJECT_THEIA_PATH}/* ${PROJECT_SRC_PATH} && cp ${Path.join(
+      `rsync -r --exclude .git --exclude npm --exclude target ${PROJECT_DEADLOCK_DESKTOP_PATH}/* ${PROJECT_SRC_PATH} && cp ${Path.join(
         __dirname,
         '.gitignore',
       )} ${PROJECT_SRC_PATH} && chown -R root:root /project`,
     );
 
     const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y");
+    await gitMission.checkout(Branch.LIVE);
     await gitMission.addAll();
     await gitMission.commit(currentDate);
     await gitMission.push();
@@ -127,5 +141,37 @@ export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom
   } catch (e) {
     error(`[${e.status}] cannot commitAndPush code: ${e.stderr}`);
     error(e.message);
+    throw new Error(e);
+  }
+}
+
+async function mergeMaster(gitMission: GitMission) {
+  try {
+    log('Merging live to master');
+
+    const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y");
+
+    await gitMission.checkout(Branch.DEFAULT);
+    await gitMission.merge(['--squash', '-X', 'theirs', Branch.LIVE]);
+    await gitMission.commit(currentDate);
+    await gitMission.push();
+    log('Merge to master done');
+    await gitMission.checkout(Branch.LIVE);
+  } catch (e) {
+    error(`[${e.status}] cannot commitAndPush code: ${e.stderr}`);
+    error(e.message);
+    throw new Error(e);
   }
 }
+
+export function getIgnorePatternFromIgnoreFile(ignoreFile: string): Promise<string[]> {
+  return fs.promises
+    .readFile(ignoreFile, { encoding: 'utf-8' })
+    .then((fileContent: string) => {
+      return fileContent.split(/\s*\r?\n\s*/);
+    })
+    .then((lines: string[]) => {
+      return lines.filter((line) => line.trimLeft().startsWith('#') || !!line.trim()).map((line) => `**/${line}`);
+    })
+    .then((filesPatterns: string[]) => [...filesPatterns, '.git']);
+}
diff --git a/deadlock-plugins/deadlock-extension/src/test/runTest.ts b/deadlock-plugins/deadlock-extension/src/test/runTest.ts
new file mode 100644
index 0000000000000000000000000000000000000000..014c3a28f7a6484adca8785f3d63a2f01ed0970f
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/test/runTest.ts
@@ -0,0 +1,23 @@
+import * as path from 'path';
+
+import { runTests } from '@vscode/test-electron';
+
+async function main() {
+  try {
+    // The folder containing the Extension Manifest package.json
+    // Passed to `--extensionDevelopmentPath`
+    const extensionDevelopmentPath = path.resolve(__dirname, '../../');
+
+    // The path to test runner
+    // Passed to --extensionTestsPath
+    const extensionTestsPath = path.resolve(__dirname, './suite/index');
+
+    // Download VS Code, unzip it and run the integration test
+    await runTests({ extensionDevelopmentPath, extensionTestsPath });
+  } catch (err) {
+    console.error('Failed to run tests');
+    process.exit(1);
+  }
+}
+
+main();
diff --git a/deadlock-plugins/deadlock-extension/src/test/suite/extension.test.ts b/deadlock-plugins/deadlock-extension/src/test/suite/extension.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..17e2eab2ae2a57eddb862d016f3a3c45c3f3041e
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/test/suite/extension.test.ts
@@ -0,0 +1,15 @@
+import * as assert from 'assert';
+
+// You can import and use all API from the 'vscode' module
+// as well as import your extension to test it
+import * as vscode from 'vscode';
+// import * as myExtension from '../../extension';
+
+suite('Extension Test Suite', () => {
+  vscode.window.showInformationMessage('Start all tests.');
+
+  test('Sample test', () => {
+    assert.strictEqual(-1, [1, 2, 3].indexOf(5));
+    assert.strictEqual(-1, [1, 2, 3].indexOf(0));
+  });
+});
diff --git a/deadlock-plugins/deadlock-extension/src/test/suite/index.ts b/deadlock-plugins/deadlock-extension/src/test/suite/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ced9b15d08a6341edb6be162920c0bbe94cb00a
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/src/test/suite/index.ts
@@ -0,0 +1,38 @@
+import * as path from 'path';
+import * as Mocha from 'mocha';
+import * as glob from 'glob';
+
+export function run(): Promise<void> {
+  // Create the mocha test
+  const mocha = new Mocha({
+    ui: 'tdd',
+    color: true,
+  });
+
+  const testsRoot = path.resolve(__dirname, '..');
+
+  return new Promise((c, e) => {
+    glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
+      if (err) {
+        return e(err);
+      }
+
+      // Add files to the test suite
+      files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
+
+      try {
+        // Run the mocha test
+        mocha.run((failures) => {
+          if (failures > 0) {
+            e(new Error(`${failures} tests failed.`));
+          } else {
+            c();
+          }
+        });
+      } catch (err) {
+        console.error(err);
+        e(err);
+      }
+    });
+  });
+}
diff --git a/deadlock-plugins/deadlock-extension/src/theia/command.ts b/deadlock-plugins/deadlock-extension/src/theia/command.ts
index 53638bd941e7cc69623287b76f5670be8e78cb2c..d8fd787c7e2289c7ee84215df89509b5ba0f19f4 100644
--- a/deadlock-plugins/deadlock-extension/src/theia/command.ts
+++ b/deadlock-plugins/deadlock-extension/src/theia/command.ts
@@ -1,4 +1,5 @@
 import { Command as VscodeComand } from 'vscode';
+
 export class Command {
   constructor(private _title: string, private command: string) {}
 
diff --git a/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts b/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts
index bf68f8424c822157b6e3d543d1afc09ec5702dcb..80ba03a989b88d6dea66723c732b19644c0514b8 100644
--- a/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts
+++ b/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts
@@ -9,7 +9,7 @@ export class DepNodeProvider implements vscode.TreeDataProvider<Action> {
   private _onDidChangeTreeData: vscode.EventEmitter<Action | undefined | void> = new vscode.EventEmitter<
     Action | undefined | void
   >();
-  // @ts-ignore
+
   readonly onDidChangeTreeData: vscode.Event<Action | undefined | void> = this._onDidChangeTreeData.event;
 
   constructor(private workspaceRoot: string) {}
diff --git a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts
index c041518b04192392f591fdc2b69c12ccc983fc11..d7c9141e5e929d5536805faa56f26630044e6f67 100644
--- a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts
@@ -1,4 +1,5 @@
 import * as fs from 'fs';
+import isDocker from 'is-docker';
 import { marked } from 'marked';
 import * as path from 'path';
 import { setInterval } from 'timers';
@@ -12,9 +13,9 @@ export const BRIEFING_ID = 'brefingView';
 export default class BriefingView extends WebviewBase {
   private briefingContent: string | undefined;
 
-  private errorLoadingBriefing: boolean = false;
+  private errorLoadingBriefing = false;
 
-  private loadingBriefing: boolean = false;
+  private loadingBriefing = false;
 
   constructor() {
     super(BRIEFING_ID, 'Briefing', OPEN_BRIEFING_COMMAND);
@@ -28,6 +29,7 @@ export default class BriefingView extends WebviewBase {
   }
 
   setupImages(text: string) {
+    //eslint-disable-next-line
     const imageRegex = /\!\[(.*?)\]\(\b(image:)(.*?\))?/g;
 
     return text.replace(imageRegex, (match, title, imagePrefix, img) => {
@@ -52,6 +54,7 @@ export default class BriefingView extends WebviewBase {
               console.error(e);
               this.briefingContent = 'Error while parsing your briefing.';
             }
+            if (isDocker()) this.show();
           },
           (error) => {
             console.error('Cannot load briefing', error);
@@ -89,7 +92,7 @@ export default class BriefingView extends WebviewBase {
     output += '<br/>';
 
     if (userConfig.getUsername()) {
-      output += this.renderUserChallengeConfig();
+      output += this.renderUserMissionConfig();
     } else {
       output += 'Loading help..';
     }
@@ -97,7 +100,7 @@ export default class BriefingView extends WebviewBase {
     return output;
   }
 
-  private renderUserChallengeConfig() {
+  private renderUserMissionConfig() {
     let adresses = '';
 
     let pathsLength = 0;
@@ -116,7 +119,7 @@ export default class BriefingView extends WebviewBase {
 
     if (pathsLength > 0) {
       return `<h3>Configuration</h3>
-      You have the following adresses availables for your challenge : <ul>${adresses}</ul>
+      You have the following adresses availables for your mission : <ul>${adresses}</ul>
       </br>
       You also have access to these paths from:
       <ul>
diff --git a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts
index daeb16529db561a4389c29535b84496c16cac449..26a90fbb943c452938ea79a3208ad63a381b7c5e 100644
--- a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts
@@ -28,42 +28,42 @@ export default class QuickSetupView extends WebviewBase {
 
   render(): string {
     return `
-      <head>
-        ${this.renderHeaderHtml()}
-      </head>
-      <body>
-        ${this.renderHtmlBody()}
-      </body>
-    `;
+         <head>
+            ${this.renderHeaderHtml()}
+         </head>
+         <body>
+            ${this.renderHtmlBody()}
+         </body>
+      `;
   }
 
   renderHtmlBody() {
     const hadMissionWorkdir = this.extensionStore.getMissionWorkdir() !== undefined;
 
     return `
-      <h1>Quick Setup</h1>
-      <div class="deadlock-getting-started-card-container">
+         <h1>Quick Setup</h1>
+         <div class="deadlock-getting-started-card-container">
 
-        ${this.renderCardHtml(
-          'Connexion à Deadlock',
-          "Tu as besoin d'être connecté à Deadlock pour continuer.",
-          { name: 'Se connecter', onClickFunctionName: 'openAuthenticationPageAction' },
-          this._isAlreadyConnected,
-          this._isAlreadyConnected,
-        )}
-        ${this.renderCardHtml(
-          'Dossier contenant tes exercices',
-          'Choisis le dossier qui contiendra tous les exercices Deadlock.',
-          {
-            name: 'Choisir un dossier',
-            onClickFunctionName: 'launchChooseMissionWorkdirAction',
-          },
-          hadMissionWorkdir,
-        )}
-      </div>
-      
-      
-      `;
+            ${this.renderCardHtml(
+              'Connexion à Deadlock',
+              "Tu as besoin d'être connecté à Deadlock pour continuer.",
+              { name: 'Se connecter', onClickFunctionName: 'openAuthenticationPageAction' },
+              this._isAlreadyConnected,
+              this._isAlreadyConnected,
+            )}
+            ${this.renderCardHtml(
+              'Dossier contenant tes exercices',
+              'Choisis le dossier qui contiendra tous les exercices Deadlock.',
+              {
+                name: 'Choisir un dossier',
+                onClickFunctionName: 'launchChooseMissionWorkdirAction',
+              },
+              hadMissionWorkdir,
+            )}
+         </div>
+         
+         
+         `;
   }
 
   renderCardHtml(
@@ -75,22 +75,22 @@ export default class QuickSetupView extends WebviewBase {
     callbackArgs?: string,
   ) {
     return `
-        <div class="deadlock-getting-started-card">
-          <vscode-checkbox ${isChecked ? 'checked' : ''} readonly> </vscode-checkbox>
-          <div class="card-body">
-            <div class="card-title">
-              ${title}
-            </div>
-            <div class="card-description">
-              ${description}
+            <div class="deadlock-getting-started-card">
+               <vscode-checkbox ${isChecked ? 'checked' : ''} readonly> </vscode-checkbox>
+               <div class="card-body">
+                  <div class="card-title">
+                     ${title}
+                  </div>
+                  <div class="card-description">
+                     ${description}
+                  </div>
+                  <vscode-button ${isDisabled ? 'disabled' : ''} onclick="${
+      button.onClickFunctionName
+    }(${callbackArgs})">${button.name}</vscode-button>
+               </div>
             </div>
-            <vscode-button ${isDisabled ? 'disabled' : ''} onclick="${button.onClickFunctionName}(${callbackArgs})">${
-      button.name
-    }</vscode-button>
-          </div>
-        </div>
-      
-      `;
+         
+         `;
   }
 
   renderHeaderHtml() {
@@ -111,11 +111,11 @@ export default class QuickSetupView extends WebviewBase {
     const customScript = this.getExternalRessourcePath(this.extensionUri, ['resources', 'js', 'gettingStartedView.js']);
 
     return `
-      <meta charset="UTF-8">
-      <script type="module" src="${toolkitUri}"></script>
-      <script type="text/javascript" src="${customScript}"></script>
-      <link href="${customStyle}" rel="stylesheet" />  
-    `;
+         <meta charset="UTF-8">
+         <script type="module" src="${toolkitUri}"></script>
+         <script type="text/javascript" src="${customScript}"></script>
+         <link href="${customStyle}" rel="stylesheet" />  
+      `;
   }
 
   onMessageReceive(message: any): void {
diff --git a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts
index 1639cb5634d43b3209661865ad8e2bb0a3dac4ee..df113cdf39c27f3fd6408f2668706fe7f1b4869d 100644
--- a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts
+++ b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts
@@ -90,17 +90,12 @@ export abstract class WebviewBase implements Disposable {
 
   async show(column: ViewColumn = ViewColumn.Beside): Promise<void> {
     if (this.panel == null) {
-      this.panel = window.createWebviewPanel(
-        this.id,
-        this.title,
-        { viewColumn: column, preserveFocus: false },
-        {
-          retainContextWhenHidden: true,
-          enableFindWidget: true,
-          enableCommandUris: true,
-          enableScripts: true,
-        },
-      );
+      this.panel = window.createWebviewPanel(this.id, this.title, ViewColumn.Active, {
+        retainContextWhenHidden: true,
+        enableFindWidget: true,
+        enableCommandUris: true,
+        enableScripts: true,
+      });
 
       this.disposablePanel = Disposable.from(
         this.panel,
diff --git a/deadlock-plugins/deadlock-extension/tsconfig.json b/deadlock-plugins/deadlock-extension/tsconfig.json
index adaa4e495b1fd3b88482adf9b1a89fb97262fbdf..87cef61e7b041014aed5ba72204c3e7fb60e3ffb 100644
--- a/deadlock-plugins/deadlock-extension/tsconfig.json
+++ b/deadlock-plugins/deadlock-extension/tsconfig.json
@@ -3,16 +3,22 @@
     "module": "commonjs",
     "target": "es2019",
     "lib": ["ES2019"],
-    "outDir": "out",
-    "sourceMap": false,
-    "strict": true,
+    "sourceMap": true,
     "rootDir": "src",
+    "outDir": "dist",
+    "strict": true,
     "noImplicitAny": false,
     "allowJs": true,
     "types": ["reflect-metadata"],
     "moduleResolution": "node",
     "experimentalDecorators": true,
     "emitDecoratorMetadata": true
+
+    /* enable all strict type-checking options */
+    /* Additional Checks */
+    // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+    // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
+    // "noUnusedParameters": true,  /* Report errors on unused parameters. */
   },
-  "exclude": ["node_modules", ".vscode-test", "front", "out", "media", "resources"]
+  "exclude": ["node_modules", ".vscode-test", "dist", "out", "media", "resources", "webpack.config.js"]
 }
diff --git a/deadlock-plugins/deadlock-extension/webpack.config.js b/deadlock-plugins/deadlock-extension/webpack.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..04a4c3e1b77664d083660cd2425e1484e1292d12
--- /dev/null
+++ b/deadlock-plugins/deadlock-extension/webpack.config.js
@@ -0,0 +1,48 @@
+//@ts-check
+
+'use strict';
+
+const path = require('path');
+
+//@ts-check
+/** @typedef {import('webpack').Configuration} WebpackConfig **/
+
+/** @type WebpackConfig */
+const extensionConfig = {
+  target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
+  mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
+
+  entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
+  output: {
+    // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
+    path: path.resolve(__dirname, 'dist'),
+    filename: 'extension.js',
+    libraryTarget: 'commonjs2',
+  },
+  externals: {
+    vscode: 'commonjs vscode', // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
+    // modules added here also need to be added in the .vscodeignore file
+  },
+  resolve: {
+    // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
+    extensions: ['.ts', '.js'],
+  },
+  module: {
+    rules: [
+      {
+        test: /\.ts$/,
+        exclude: /node_modules/,
+        use: [
+          {
+            loader: 'ts-loader',
+          },
+        ],
+      },
+    ],
+  },
+  devtool: 'nosources-source-map',
+  infrastructureLogging: {
+    level: 'log', // enables logging required for problem matchers
+  },
+};
+module.exports = [extensionConfig];
diff --git a/plugins/.gitkeep b/plugins/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/plugins/gitlens-10.2.3.vsix b/plugins/gitlens-10.2.3.vsix
deleted file mode 100644
index 248629ac5c2accb40160dfc108b9026f43869ed2..0000000000000000000000000000000000000000
Binary files a/plugins/gitlens-10.2.3.vsix and /dev/null differ
diff --git a/setup.sh b/setup.sh
index 2ebb8e0d4157f9d08fc87605c996fc2daf1e1085..3cfcf6de32b76061ba02167715bf2fa1bee97443 100755
--- a/setup.sh
+++ b/setup.sh
@@ -1,2 +1,3 @@
 npm install
-npm install --prefix ./deadlock-plugins/deadlock-extension
\ No newline at end of file
+npm install --prefix ./deadlock-plugins/deadlock-extension
+npm install --prefix ./deadlock-plugins/deadlock-extension/src/recorder
\ No newline at end of file
diff --git a/setup_trace.py b/setup_trace.py
index 313589500a92f3dd57d6be106950d9382fe7a730..80f70c3c9d60d86bda52a33a14a72ccac9379fae 100644
--- a/setup_trace.py
+++ b/setup_trace.py
@@ -1,7 +1,7 @@
 
-open('/home/theia/.bash_history', 'a').close()
+open('/home/deadlock/.bash_history', 'a').close()
 
-bashrc = open('/home/theia/.bashrc', 'a')
+bashrc = open('/home/deadlock/.bashrc', 'a')
 bashrc.write('\n')
 bashrc.write('HISTCONTROL=""')
 bashrc.write('\n')
diff --git a/start.sh b/start.desktop.sh
old mode 100755
new mode 100644
similarity index 63%
rename from start.sh
rename to start.desktop.sh
index c45a90336ab9b77e6160e4c17e4341791922076f..21d2886351fbea5236b8ceeece5a5c2069311d5a
--- a/start.sh
+++ b/start.desktop.sh
@@ -3,6 +3,9 @@
 ON_START_UP_FILE="/deadlock/startup.sh"
 TAG="[DEADLOCK]"
 
+# Start docker in docker
+dockerd-entrypoint.sh $@ &
+
 # setup ssh key for root user
 # must be installed by the API first within /tmp/.ssh
 mkdir ~/.ssh
@@ -20,13 +23,15 @@ else
     echo
 fi
 
+
+su deadlock -c "sudo python /setup_trace.py"
+
+
 # start command recorder
-node deadlock/recorder.js &
+node deadlock/recorder.js
+
+
+
 
-deluser theia sudo
 
-su theia --command "python setup_trace.py"
-rm setup_trace.py
 
-# starting theia as THEIA
-su theia --command "node /home/theia/src-gen/backend/main.js /home/project --hostname=0.0.0.0 --plugins=local-dir:/home/plugins"