diff --git a/.gitignore b/.gitignore
index 45de4116fd5ee5a5a2a2612157301ce75d7bffed..a5cafce8aaff50784bfa58d9c64c38392092c4e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
-.env
-
 aws.xml
 workspace.xml
+.gitlab-ci-local
+Wiki/.idea
 
 ############################ MacOS
 # General
@@ -184,11 +184,10 @@ web_modules/
 .yarn-integrity
 
 # dotenv environment variable files
-.env
-.env.development.local
-.env.test.local
-.env.production.local
-.env.local
+.env*
+.flaskenv*
+!.env.project
+!.env.vault
 
 # parcel-bundler cache (https://parceljs.org/)
 .cache
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9e3ac9177517205ddc9034c3a05eefcd52eebd57..46b9417d91ca72665753b9af283498ad3ac10557 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,300 +1,8 @@
-variables:
-    GIT_SUBMODULE_STRATEGY: recursive
-    GIT_SUBMODULE_FORCE_HTTPS: "true"
-    SECURE_FILES_DOWNLOAD_PATH: './'
+include: "NodeApp/.gitlab-ci/**.yml"
 
-    BIN_NAME: dojo
-
-    MACOS_PKG_EXTENSION: '.pkg'
-    MACOS_PKG_BIN_NAME: "${BIN_NAME}${MACOS_PKG_EXTENSION}"
-
-    WINDOWS_BIN_EXTENSION: '.exe'
-    WINDOWS_BIN_NAME: "${BIN_NAME}${WINDOWS_BIN_EXTENSION}"
-
-    ARTIFACTS_FOLDER: /artifacts
-
-    GITLAB_API_PROJECT_URL: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}
-
-    BIN_FOLDER_MACOS: $ARTIFACTS_FOLDER/macOS
-    BIN_FOLDER_LINUX: $ARTIFACTS_FOLDER/Linux
-    BIN_FOLDER_WINDOWS: $ARTIFACTS_FOLDER/Windows
-
-    BIN_FOLDER_MACOS_ARM64: $BIN_FOLDER_MACOS/arm64
-    BIN_FOLDER_MACOS_X64: $BIN_FOLDER_MACOS/x64
-
-    BIN_FILE_MACOS_ARM64: $BIN_FOLDER_MACOS_ARM64/$BIN_NAME
-    BIN_FILE_MACOS_X64: $BIN_FOLDER_MACOS_X64/$BIN_NAME
-    BIN_PKG_FILE_MACOS_ARM64: $BIN_FOLDER_MACOS_ARM64/$MACOS_PKG_BIN_NAME
-    BIN_PKG_FILE_MACOS_X64: $BIN_FOLDER_MACOS_X64/$MACOS_PKG_BIN_NAME
-    BIN_FILE_LINUX_ARM64: $BIN_FOLDER_LINUX/arm64/$BIN_NAME
-    BIN_FILE_LINUX_X64: $BIN_FOLDER_LINUX/x64/$BIN_NAME
-    BIN_FILE_WINDOWS_ARM64: $BIN_FOLDER_WINDOWS/arm64/$WINDOWS_BIN_NAME
-    BIN_FILE_WINDOWS_X64: $BIN_FOLDER_WINDOWS/x64/$WINDOWS_BIN_NAME
-
-    VERSION_FILE: $ARTIFACTS_FOLDER/VERSION
-    VERSION_DEV_SUFFIX: '-dev'
-
-    PROJECT_FOLDER: NodeApp
-
-    PACKAGE_REGISTRY_URL: "${GITLAB_API_PROJECT_URL}/packages/generic/${BIN_NAME}"
-
-
-.get_version:
-    script:
-        - IS_DEV=$([[ $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ]] && echo false || echo true)
-        - VERSION=$(jq -r .version $PROJECT_FOLDER/package.json)$([[ $IS_DEV == true ]] && echo $VERSION_DEV_SUFFIX || echo '')
-
-.get_packages_url:
-    script:
-        - PACKAGE_URL_MACOS_ARM64_BIN="${PACKAGE_REGISTRY_URL}_macOS-arm64/${VERSION}/${BIN_NAME}"
-        - PACKAGE_URL_MACOS_X64_BIN="${PACKAGE_REGISTRY_URL}_macOS-x64/${VERSION}/${BIN_NAME}"
-        - PACKAGE_URL_MACOS_ARM64_PKG="${PACKAGE_REGISTRY_URL}_macOS-pkg-arm64/${VERSION}/${MACOS_PKG_BIN_NAME}"
-        - PACKAGE_URL_MACOS_X64_PKG="${PACKAGE_REGISTRY_URL}_macOS-pkg-x64/${VERSION}/${MACOS_PKG_BIN_NAME}"
-        - PACKAGE_URL_LINUX_ARM64_BIN="${PACKAGE_REGISTRY_URL}_Linux-arm64/${VERSION}/${BIN_NAME}"
-        - PACKAGE_URL_LINUX_X64_BIN="${PACKAGE_REGISTRY_URL}_Linux-x64/${VERSION}/${BIN_NAME}"
-        - PACKAGE_URL_WINDOWS_ARM64_BIN="${PACKAGE_REGISTRY_URL}_Windows-arm64/${VERSION}/${WINDOWS_BIN_NAME}"
-        - PACKAGE_URL_WINDOWS_X64_BIN="${PACKAGE_REGISTRY_URL}_Windows-x64/${VERSION}/${WINDOWS_BIN_NAME}"
-
-.build_cli:
-    script:
-        - cd NodeApp
-        # Download secure files
-        - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash
-        - mv env_$VERSION .env
-        # Install dependencies
-        - npm install
-        - npm run build
-        # Build binaries
-        ## macOS
-        - npx pkg . -t node18-macos-arm64 --output $BIN_FILE_MACOS_ARM64 --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-macos-x64 --output $BIN_FILE_MACOS_X64 --no-bytecode --public-packages "*" --public
-        ## Linux
-        - npx pkg . -t node18-linuxstatic-arm64 --output $BIN_FILE_LINUX_ARM64 --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-linuxstatic-x64 --output $BIN_FILE_LINUX_X64 --no-bytecode --public-packages "*" --public
-        ## Windows
-        - npx pkg . -t node18-win-arm64 --output $BIN_FILE_WINDOWS_ARM64 --no-bytecode --public-packages "*" --public
-        - npx pkg . -t node18-win-x64 --output $BIN_FILE_WINDOWS_X64 --no-bytecode --public-packages "*" --public
-
-.sign_macos:
-    script:
-        # Sign excecutable
-        - codesign --force --options=runtime --entitlements ../../../Resources/macApp/Signing/entitlements.plist --sign $SIGN_DEV_ID_APP --keychain $SIGN_LOGIN_KEYCHAIN_PATH --timestamp ${BIN_NAME}
-        # Package and notarize the app
-        - xcrun notarytool store-credentials --apple-id $SIGN_APPLE_ID --team-id $SIGN_TEAM_ID --password $SIGN_APP_PASSWORD --keychain $SIGN_LOGIN_KEYCHAIN_PATH $SIGN_KEYCHAIN_PROFILE
-        - ditto ${BIN_NAME} ${BIN_NAME}_pkg/usr/local/bin/
-        - productbuild --identifier $SIGN_IDENTIFIER --version $VERSION --sign $SIGN_DEV_ID_INST --keychain $SIGN_LOGIN_KEYCHAIN_PATH --timestamp --root ${BIN_NAME}_pkg / ${MACOS_PKG_BIN_NAME}
-        - xcrun notarytool submit ${BIN_NAME}.pkg --keychain $SIGN_LOGIN_KEYCHAIN_PATH --keychain-profile $SIGN_KEYCHAIN_PROFILE --wait
-        - xcrun stapler staple ${BIN_NAME}.pkg
-        #Clean folder
-        - rm -Rf ${BIN_NAME}_pkg
-
-.clean_release:
-    script:
-        # Delete release if it already exists
-        - 'curl --request DELETE --header "JOB-TOKEN: $CI_JOB_TOKEN" "${GITLAB_API_PROJECT_URL}/releases/${VERSION}"'
-        # Delete tag if it already exists (use private-token because job-token don't have permission to delete tags)
-        - 'curl --request DELETE --header "PRIVATE-TOKEN: $GITLAB_PROJECT_ACCESS_TOKEN" "${GITLAB_API_PROJECT_URL}/repository/tags/${VERSION}"'
-
-.clean_packages:
-    script:
-        # Get all packages of the project
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" "${GITLAB_API_PROJECT_URL}/packages" > gitlabPackages.json'
-        # Filter and select packages to delete (based on version)
-        - packagesToDelete=`jq -r '.[] | select(.version=="'${VERSION}'") | ._links.delete_api_path' gitlabPackages.json`
-        # Delete packages by calling Gitlab API
-        - >
-            for deletePath in $packagesToDelete; do
-              echo "Deleting package at path : ${deletePath}"
-              curl --request DELETE --header "JOB-TOKEN: $CI_JOB_TOKEN" "${deletePath}"
-            done
-
-
-stages:
-    - test
-    - build
-    - sign
-    - clean
-    - upload
-    - release
-
-
-test:build:
-    stage: test
-    tags:
-        - build
-    image: node:latest
-    script:
-        - apt update
-        - apt install -y jq
-        - !reference [.get_version, script]
-        - !reference [.build_cli, script]
-    rules:
-        - if: '$CI_COMMIT_TAG =~ "/^$/" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_COMMIT_BRANCH !~ /^v[0-9]+(\.[0-9]+)*$/'
-
-build:version:
-    stage: build
-    tags:
-        - build
-    image: node:latest
-    script:
-        - apt update
-        - apt install -y jq
-        - !reference [.get_version, script]
-        - mkdir -p $ARTIFACTS_FOLDER
-        - echo $VERSION > $VERSION_FILE
-        - !reference [.build_cli, script]
-    artifacts:
-        untracked: true
-        paths:
-            - $ARTIFACTS_FOLDER/*
-        expire_in: 1 hour
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
-
-sign:macos:
-    stage: sign
-    tags:
-        - macos_signing
-    dependencies:
-        - build:version
-    script:
-        - VERSION=$(cat $VERSION_FILE)
-        - security unlock-keychain -p $SIGN_KEYCHAIN_PASSWORD $SIGN_LOGIN_KEYCHAIN_PATH
-        - cd $BIN_FOLDER_MACOS_ARM64
-        - !reference [.sign_macos, script]
-        - cd $BIN_FOLDER_MACOS_X64
-        - !reference [.sign_macos, script]
-    artifacts:
-        paths:
-            - $ARTIFACTS_FOLDER/*
-        expire_in: 1 day
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
-
-clean:release:
-    stage: clean
-    tags:
-        - gitlab_clean
-    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
-    script:
-        - !reference [.get_version, script]
-        - !reference [.clean_release, script]
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
-
-clean:packages:
-    stage: clean
-    tags:
-        - gitlab_clean
-    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
-    script:
-        - !reference [.get_version, script]
-        - !reference [.clean_packages, script]
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
-
-clean:dev:release:
-    stage: clean
-    tags:
-        - gitlab_clean
-    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
-    script:
-        - !reference [.get_version, script]
-        - VERSION="${VERSION}${VERSION_DEV_SUFFIX}"
-        - !reference [.clean_release, script]
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
-
-clean:dev:packages:
-    stage: clean
-    tags:
-        - gitlab_clean
-    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
-    script:
-        - !reference [.get_version, script]
-        - VERSION="${VERSION}${VERSION_DEV_SUFFIX}"
-        - !reference [.clean_packages, script]
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
-
-upload:packages:
-    stage: upload
-    tags:
-        - gitlab_package
-    dependencies:
-        - sign:macos
-    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
-    script:
-        - !reference [.get_version, script]
-        - !reference [.get_packages_url, script]
-        #macOS
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_MACOS_ARM64} "${PACKAGE_URL_MACOS_ARM64_BIN}";'
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_MACOS_X64} "${PACKAGE_URL_MACOS_X64_BIN}";'
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_MACOS_ARM64} "${PACKAGE_URL_MACOS_ARM64_PKG}";'
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_MACOS_X64} "${PACKAGE_URL_MACOS_X64_PKG}";'
-        #Linux
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_LINUX_ARM64} "${PACKAGE_URL_LINUX_ARM64_BIN}";'
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_LINUX_X64} "${PACKAGE_URL_LINUX_X64_BIN}";'
-        #Windows
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_WINDOWS_ARM64} "${PACKAGE_URL_WINDOWS_ARM64_BIN}";'
-        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_WINDOWS_X64} "${PACKAGE_URL_WINDOWS_X64_BIN}";'
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
-
-release:gitlab:
-    stage: release
-    tags:
-        - release
-    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+lint_pass:
+    only:
+        variables:
+            - $FOO == "bar"
     script:
-        - !reference [.get_version, script]
-        - !reference [.get_packages_url, script]
-        - echo 'Running release_job'
-        # Extract description from CHANGELOG.md
-        - CHANGELOG_LINE_START=`awk '/##\ [0-9]+\.[0-9]+\.[0-9]+/{print NR; exit;}' CHANGELOG.md`
-        - CHANGELOG_LINE_END=`awk '/##\ [0-9]+\.[0-9]+\.[0-9]+/{ count++; if(count>1) {print NR; exit;}}' CHANGELOG.md`
-        - DESCRIPTION=`awk 'NR > '$CHANGELOG_LINE_START' && NR < '$CHANGELOG_LINE_END'' CHANGELOG.md`
-        # Create Release (can't be done by release_step of gitlab image because it don't have access to env var defined in script_step)
-        - >
-            RELEASE_DATA=$(jq --null-input --arg version "$VERSION" --arg description "# Changelog (version $VERSION) $DESCRIPTION" --arg tag_name "$VERSION" --arg ref "$CI_COMMIT_SHORT_SHA" '{
-                "name": $version,
-                "description": $description,
-                "tag_name": $tag_name,
-                "ref": $ref,
-                "assets": {
-                    "links": [
-                        {
-                          "name": "Windows (ARM64) binary",
-                          "url": "'${PACKAGE_URL_WINDOWS_ARM64_BIN}'",
-                        },{
-                            "name": "Windows (x64) binary",
-                            "url": "'${PACKAGE_URL_WINDOWS_X64_BIN}'",
-                        },{
-                            "name": "Linux (ARM64) binary",
-                            "url": "'${PACKAGE_URL_LINUX_ARM64_BIN}'",
-                        },{
-                            "name": "Linux (x64) binary",
-                            "url": "'${PACKAGE_URL_LINUX_X64_BIN}'",
-                        },{
-                            "name": "macOS (Intel) binary",
-                            "url": "'${PACKAGE_URL_MACOS_X64_BIN}'",
-                        },{
-                          "name": "macOS (Apple Silicon) binary",
-                          "url": "'${PACKAGE_URL_MACOS_ARM64_BIN}'",
-                        },{
-                            "name": "macOS (Intel) package",
-                            "url": "'${PACKAGE_URL_MACOS_X64_PKG}'",
-                        },{
-                          "name": "macOS (Apple Silicon) package",
-                          "url": "'${PACKAGE_URL_MACOS_ARM64_PKG}'",
-                        }
-                    ]                       
-                }
-            }')
-        - >
-            curl --data "${RELEASE_DATA}" \
-              --header "Content-Type: application/json" \
-              --header "JOB-TOKEN: $CI_JOB_TOKEN" \
-              --request POST "${GITLAB_API_PROJECT_URL}/releases"
-    rules:
-        - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /^v[0-9]+(\.[0-9]+)*$/'
\ No newline at end of file
+        - echo
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 619aa96399baa4168efc9ee2bc236f249f2664d1..1bc7131614fb2ae150155b19cdc4dd631d137e12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,7 +14,24 @@
 **⚠️ Deprecation:**
 -->
 
-## 2.0.0 (?)
+## 2.1.0 (?)
+
+### ✨ Feature
+- Added pipeline badge to exercises
+- Creation of Debian / Ubuntu deb packages
+
+### 🎨 Interface
+- **πŸ’₯ Breaking:** Renamed `dojo.enonce` (or `dojo.assignment`) file to `dojo_assignment.json`
+
+### πŸ”¨ Internal / Developers
+- Deploy Wiki on Gitlab (on push to `main`) from files of `Wiki` folder
+- Migration from .env files stored in Gitlab Secure Files to usage of `dotenv-vault` (locally)
+
+### πŸ“š Documentation
+- Added Wiki base
+
+
+## 2.0.0 (2023-09-15)
 
 ### ✨ Feature
 - Added license: AGPLv3
diff --git a/NodeApp/.env.vault b/NodeApp/.env.vault
new file mode 100644
index 0000000000000000000000000000000000000000..f6d35a5f86ea190e012c9ec8d378bab125ef1e2f
--- /dev/null
+++ b/NodeApp/.env.vault
@@ -0,0 +1,11 @@
+#/-------------------.env.vault---------------------/
+#/         cloud-agnostic vaulting standard         /
+#/   [how it works](https://dotenv.org/env-vault)   /
+#/--------------------------------------------------/
+
+# development
+DOTENV_VAULT_DEVELOPMENT="McsEkttfKr1Vl0q9g7z4+6IRodJFBiT+rZWlz8SH12VCeviOBsot3YnUku80PwUxI3MqaWKmw6WNL5eLxKLlo64coMfgdajaTcp9yOfK6CRfHfWdh3MCoAf8ZiqbJGkmaH2X8j2QcnzJ6C+v8S1ZPUxk49ug+6otlyKl8hnr9ECvNGFKJ+Xa5L7XzEo+IGIFDrEYDtxI2VyUOiwudRnP0WarU8KJNt28IZYz3M5zymdFFI8Wlcq2+KiOp/CjiKYDxALkcINGkffu1WIU/lS0WE1FVLbds2hMsGkB4LwT1Q1ASkmsVT/BIb/wRxamDmAN494cTgGqYdaM5IOCGt2BDtm2UJWFrM5txl/PKRrbgE8wjpIaSp5OQ33nRV2P1fGk38z3gYHVI3NG5SRzxZTo+D4lT9UdNmwWIzL6rXRfnJgUTwKhc0MBrl+giaIt3U8wzYB69/F5+thYruSJVir42/b+XpOWSovZTwYYcAO5dXML/24jR3eNMxTlcxVvXpdx/Eg8r5ZCHSsMVKCgmyfGA49xWGjaMqOiizu83mt9KhsXiRgaI1imKiOm85eK9CUkvfLTQo8ccK+RITMvLKtCZgirF4HLi7y5DVjvufhtjxxOXjknFmI3UJFmjU9cUAKC3ccsM9F8Pm4mo6XbcPjBXZdX/18gtlvxps5at1cH998F8ZPkoaEJGp7lCYlxXTEBHOxxCEd5DdUldhpbOUfSsYZHUuxiA1gqJvilok39bgxl1WpO6nPM7S0S0GaI1jGkPKOJ/gx1fBRY91sSQy9Qw/O3tBUId1Az0QZLQZ+gijr6kchd5aczHmIRa2z4AHCSbeuzmaGfP+4yh0M6FvPPCD4i"
+
+# production
+DOTENV_VAULT_PRODUCTION="aWWYhhCla0zC0MtLgZl1O7b4j8q5ya47bbHgZZtNJzw1PrL1I/2axdy6atW3v1cstw2putaNl4Gc81IM3GUPHyP6dDod6L7AMmLXKwrQFoYUxz0Za8fWLpnx79nY6A/zNgwfBqEZ0NE5o/GFKCDRYsfA6UuX8f6jBN2lhVK9leMU5DRvEyPrhKV4KHDwjKSTuqNbkZNW/BwyTf9Fdrd/SgUjgWA5Rvrg6N3RSkcHsuHfrBXzuzFHUFjQyrDlfS+fmpHj6PN69HWwtG+OjpgPaLocZ3WN2cDnb9X+rhB1W0uTN9Y8gAJkddUw3Kynf7YXimEBxWwV3ltdftIPAIcnz5cOx6lbzwFrXPnl2FesjpFZ1G27rZVr61kSUiILjRbOg9KIEmSqJXFzUHEyX7FwEYWxHtm1jw+76ePTV5g+4yfIxx2Vjo78uUKreASwtlA6CnsnnkFKqqLE3LYtskI7SYq/2t/Y0UrFKOFrOiK3Y5Kza7rRfcZo5SoNGFcyBw+4/YV5Tk/8z4zhyt/6lzLTA/w/mNXv4KCKn2oRBIUOlaMClvfmA2pwCv7YgpCGAycj0qQkhNhhIkd2F3cuc0o+U1XnWiqlEIVX9Z40gnrzodTRBmdvjVNdQ79nMvEVsmzjwmhoAC62RnyEnMUBrE9XM3RvRFoYFThOd7RE5TxCmLjbZfyVYN58hufZZDFT3oPYzoT9rzur6nU0NqjfNNU6BfZK4L+qGBg="
+
diff --git a/NodeApp/.gitignore b/NodeApp/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..797ca4d1e519b7f376d5d3f74b9564fe39bd2079
--- /dev/null
+++ b/NodeApp/.gitignore
@@ -0,0 +1,5 @@
+
+.env*
+.flaskenv*
+!.env.project
+!.env.vault
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/00_vars.yml b/NodeApp/.gitlab-ci/00_vars.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b2f058ad22a29824086741b5e0199b107a698ee7
--- /dev/null
+++ b/NodeApp/.gitlab-ci/00_vars.yml
@@ -0,0 +1,54 @@
+variables:
+    GIT_SUBMODULE_STRATEGY: recursive
+    GIT_SUBMODULE_FORCE_HTTPS: "true"
+    SECURE_FILES_DOWNLOAD_PATH: './'
+
+    PROJECT_NAME: DojoCLI
+    PROJECT_FOLDER: NodeApp
+
+    RESOURCES_FOLDER: "${CI_PROJECT_DIR}/Resources"
+
+    BIN_NAME: dojo
+
+    PKG_EXTENSION_DEBIAN: '.deb'
+    PKG_EXTENSION_MACOS: '.pkg'
+
+    PKG_BIN_NAME_DEBIAN: "${BIN_NAME}${PKG_EXTENSION_DEBIAN}"
+    PKG_BIN_NAME_MACOS: "${BIN_NAME}${PKG_EXTENSION_MACOS}"
+
+    BIN_EXTENSION_WINDOWS: '.exe'
+    BIN_NAME_WINDOWS: "${BIN_NAME}${BIN_EXTENSION_WINDOWS}"
+
+    ARTIFACTS_FOLDER: /artifacts
+
+    GITLAB_API_PROJECT_URL: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}
+
+    BIN_FOLDER_MACOS: $ARTIFACTS_FOLDER/macOS
+    BIN_FOLDER_LINUX: $ARTIFACTS_FOLDER/Linux
+    BIN_FOLDER_WINDOWS: $ARTIFACTS_FOLDER/Windows
+
+    BIN_FOLDER_LINUX_ARM64: $BIN_FOLDER_LINUX/arm64
+    BIN_FOLDER_LINUX_X64: $BIN_FOLDER_LINUX/x64
+    BIN_FOLDER_MACOS_ARM64: $BIN_FOLDER_MACOS/arm64
+    BIN_FOLDER_MACOS_X64: $BIN_FOLDER_MACOS/x64
+    BIN_FOLDER_WINDOWS_ARM64: $BIN_FOLDER_WINDOWS/arm64
+    BIN_FOLDER_WINDOWS_X64: $BIN_FOLDER_WINDOWS/x64
+
+    BIN_FILE_MACOS_ARM64: $BIN_FOLDER_MACOS_ARM64/$BIN_NAME
+    BIN_FILE_MACOS_X64: $BIN_FOLDER_MACOS_X64/$BIN_NAME
+    BIN_FILE_LINUX_ARM64: $BIN_FOLDER_LINUX_ARM64/$BIN_NAME
+    BIN_FILE_LINUX_X64: $BIN_FOLDER_LINUX_X64/$BIN_NAME
+    BIN_FILE_WINDOWS_ARM64: $BIN_FOLDER_WINDOWS_ARM64/$BIN_NAME_WINDOWS
+    BIN_FILE_WINDOWS_X64: $BIN_FOLDER_WINDOWS_X64/$BIN_NAME_WINDOWS
+
+    BIN_PKG_FILE_DEBIAN_ARM64: $BIN_FOLDER_LINUX_ARM64/$PKG_BIN_NAME_DEBIAN
+    BIN_PKG_FILE_DEBIAN_X64: $BIN_FOLDER_LINUX_X64/$PKG_BIN_NAME_DEBIAN
+    BIN_PKG_FILE_MACOS_ARM64: $BIN_FOLDER_MACOS_ARM64/$PKG_BIN_NAME_MACOS
+    BIN_PKG_FILE_MACOS_X64: $BIN_FOLDER_MACOS_X64/$PKG_BIN_NAME_MACOS
+
+    VERSION_FILE: $ARTIFACTS_FOLDER/VERSION
+    VERSION_DEV_SUFFIX: '-dev'
+
+    PACKAGE_REGISTRY_URL: "${GITLAB_API_PROJECT_URL}/packages/generic/${BIN_NAME}"
+
+    WIKI_FOLDER: Wiki
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/01_functions.yml b/NodeApp/.gitlab-ci/01_functions.yml
new file mode 100644
index 0000000000000000000000000000000000000000..57b72e642b5194d76bb1a6176bd6a48ec9872b7f
--- /dev/null
+++ b/NodeApp/.gitlab-ci/01_functions.yml
@@ -0,0 +1,108 @@
+.get_version:
+    script:
+        - IS_DEV=$([[ $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ]] && echo false || echo true)
+        - VERSION=$(jq -r .version $PROJECT_FOLDER/package.json)$([[ $IS_DEV == true ]] && echo $VERSION_DEV_SUFFIX || echo '')
+
+
+.get_last_stable_version:
+    script:
+        # Get all releases of the project
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" "${GITLAB_API_PROJECT_URL}/releases" > releases.json'
+
+        # Filter and select last package that don't contains "-dev" in its name
+        - LAST_STABLE_VERSION=`jq -r '[.[] | .name | select (contains("$VERSION_DEV_SUFFIX") | not)][0]' releases.json`
+
+
+.get_packages_url:
+    script:
+        # Binaries
+        - PACKAGE_URL_MACOS_ARM64_BIN="${PACKAGE_REGISTRY_URL}_macOS-arm64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_MACOS_X64_BIN="${PACKAGE_REGISTRY_URL}_macOS-x64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_LINUX_ARM64_BIN="${PACKAGE_REGISTRY_URL}_Linux-arm64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_LINUX_X64_BIN="${PACKAGE_REGISTRY_URL}_Linux-x64/${VERSION}/${BIN_NAME}"
+        - PACKAGE_URL_WINDOWS_ARM64_BIN="${PACKAGE_REGISTRY_URL}_Windows-arm64/${VERSION}/${BIN_NAME_WINDOWS}"
+        - PACKAGE_URL_WINDOWS_X64_BIN="${PACKAGE_REGISTRY_URL}_Windows-x64/${VERSION}/${BIN_NAME_WINDOWS}"
+
+        # Packages
+        - PACKAGE_URL_MACOS_ARM64_PKG="${PACKAGE_REGISTRY_URL}_macOS-pkg-arm64/${VERSION}/${PKG_BIN_NAME_MACOS}"
+        - PACKAGE_URL_MACOS_X64_PKG="${PACKAGE_REGISTRY_URL}_macOS-pkg-x64/${VERSION}/${PKG_BIN_NAME_MACOS}"
+        - PACKAGE_URL_DEBIAN_ARM64_PKG="${PACKAGE_REGISTRY_URL}_debian-pkg-arm64/${VERSION}/${PKG_BIN_NAME_DEBIAN}"
+        - PACKAGE_URL_DEBIAN_X64_PKG="${PACKAGE_REGISTRY_URL}_debian-pkg-x64/${VERSION}/${PKG_BIN_NAME_DEBIAN}"
+
+        # Wiki
+        - WIKI_ARCHIVE_NAME="${PROJECT_NAME}_Wiki_${VERSION}.tar.xz"
+        - PACKAGE_URL_WIKI="${PACKAGE_REGISTRY_URL}_Wiki/${VERSION}/${WIKI_ARCHIVE_NAME}"
+
+
+.build_cli:
+    script:
+        - cd "${PROJECT_FOLDER}"
+
+        # Install dependencies
+        - npm install
+
+        # Set version number shown in CLI
+        - sed -i -r "s/\{\{VERSION\}\}/${VERSION}/g" src/commander/CommanderApp.ts
+
+        # Decrypt env vars for production
+        - |
+            if [ $CI_COMMIT_REF_PROTECTED == "true" ]; then
+                echo "Decrypt production env vars"
+                sed -i -r "s/(DOTENV_KEY[ ]*:[ ]*[\'\"\`])[^'\"\`]*([\'\"\`])([ ]*\,)?//g" src/app.ts
+                sed -i -r "s/,[\ \n]*\}/\}/g" src/app.ts
+                npx dotenv-vault local decrypt "${DOTENV_PROD_KEY}" > .env
+            fi
+
+        # Build
+        - npm run build
+
+        # Build binaries
+        ## macOS
+        - npx pkg . -t node18-macos-arm64 --output $BIN_FILE_MACOS_ARM64 --no-bytecode --compress Brotli --public-packages "*" --public
+        - npx pkg . -t node18-macos-x64 --output $BIN_FILE_MACOS_X64 --no-bytecode --compress Brotli --public-packages "*" --public
+
+        ## Linux
+        - npx pkg . -t node18-linuxstatic-arm64 --output $BIN_FILE_LINUX_ARM64 --no-bytecode --compress Brotli --public-packages "*" --public
+        - npx pkg . -t node18-linuxstatic-x64 --output $BIN_FILE_LINUX_X64 --no-bytecode --compress Brotli --public-packages "*" --public
+
+        ## Windows
+        - npx pkg . -t node18-win-arm64 --output $BIN_FILE_WINDOWS_ARM64 --no-bytecode --compress Brotli --public-packages "*" --public
+        - npx pkg . -t node18-win-x64 --output $BIN_FILE_WINDOWS_X64 --no-bytecode --compress Brotli --public-packages "*" --public
+
+        # Add execution rights to binaries
+        ## macOS
+        - chmod +x $BIN_FILE_MACOS_ARM64
+        - chmod +x $BIN_FILE_MACOS_X64
+
+        ## Linux
+        - chmod +x $BIN_FILE_LINUX_ARM64
+        - chmod +x $BIN_FILE_LINUX_X64
+
+        ## Windows
+        - chmod +x $BIN_FILE_WINDOWS_ARM64
+        - chmod +x $BIN_FILE_WINDOWS_X64
+
+
+.clean_release:
+    script:
+        # Delete release if it already exists
+        - 'curl --request DELETE --header "JOB-TOKEN: $CI_JOB_TOKEN" "${GITLAB_API_PROJECT_URL}/releases/${VERSION}"'
+
+        # Delete tag if it already exists (use private-token because job-token don't have permission to delete tags)
+        - 'curl --request DELETE --header "PRIVATE-TOKEN: $GITLAB_PROJECT_ACCESS_TOKEN" "${GITLAB_API_PROJECT_URL}/repository/tags/${VERSION}"'
+
+
+.clean_packages:
+    script:
+        # Get all packages of the project
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" "${GITLAB_API_PROJECT_URL}/packages" > gitlabPackages.json'
+
+        # Filter and select packages to delete (based on version)
+        - packagesToDelete=`jq -r '.[] | select(.version=="'${VERSION}'") | ._links.delete_api_path' gitlabPackages.json`
+
+        # Delete packages by calling Gitlab API
+        - >
+            for deletePath in $packagesToDelete; do
+              echo "Deleting package at path : ${deletePath}"
+              curl --request DELETE --header "JOB-TOKEN: $CI_JOB_TOKEN" "${deletePath}"
+            done
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/02_templates.yml b/NodeApp/.gitlab-ci/02_templates.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8bf24a6f5a203cdb1ea621d04d0091a785bbd960
--- /dev/null
+++ b/NodeApp/.gitlab-ci/02_templates.yml
@@ -0,0 +1,90 @@
+.pkg_and_sign:debian:
+    stage: pkg_and_sign
+    image: ubuntu:latest
+    tags:
+        - pkg
+    dependencies:
+        - build:version
+    script:
+        # Install dependencies
+        - apt update
+        - apt install -y dpkg jq curl build-essential
+
+        # Get vars
+        - !reference [ .get_version, script ]
+        - !reference [ .get_last_stable_version, script ]
+
+        - cd $BIN_FOLDER_DEBIAN_PKG_AND_SIGN
+        - PKG_BUILD_FOLDER_NAME="${BIN_NAME}_${VERSION}_${ARCH}"
+
+
+        # Pkg tree creation
+        - mkdir -p "${PKG_BUILD_FOLDER_NAME}/usr/local/bin/"
+        ## Copy binary
+        - cp -R ${BIN_NAME} "${PKG_BUILD_FOLDER_NAME}/usr/local/bin/"
+        ## Copy debian folder with package definition files
+        - cp -R "${RESOURCES_FOLDER}/Debian/pkg/DEBIAN" "${PKG_BUILD_FOLDER_NAME}"
+
+        # Modify files
+        - cd "${PKG_BUILD_FOLDER_NAME}/DEBIAN"
+        ## control file
+        - sed -i -r "s%\{\{VERSION\}\}%${VERSION}%g" control
+        - sed -i -r "s%\{\{ARCH\}\}%${ARCH}%g" control
+        - sed -i -r "s%\{\{BIN_NAME\}\}%${BIN_NAME}%g" control
+        ## changelog file
+        - STABILITY=$([[ $IS_DEV == true ]] && echo 'unstable' || echo 'stable')
+        - PRIORITY=$([[ ${VERSION%.*} == ${LAST_STABLE_VERSION%.*} ]] && echo 'medium' || echo 'high')
+        - sed -i -r "s%\{\{VERSION\}\}%${VERSION}%g" changelog
+        - sed -i -r "s%\{\{BIN_NAME\}\}%${BIN_NAME}%g" changelog
+        - sed -i -r "s%\{\{DATE\}\}%$(date -R)%g" changelog
+        - sed -i -r "s%\{\{URL\}\}%${CI_PROJECT_URL}%g" changelog
+        - sed -i -r "s%\{\{STABILITY\}\}%${STABILITY}%g" changelog
+        - sed -i -r "s%\{\{PRIORITY\}\}%${PRIORITY}%g" changelog
+        ## copyright file
+        - sed -i -r "s%\{\{BIN_NAME\}\}%${BIN_NAME}%g" copyright
+        ## return to bin folder
+        - cd $BIN_FOLDER_DEBIAN_PKG_AND_SIGN
+
+        # Build package
+        - dpkg-deb --build --root-owner-group -Z xz -z 9 ${PKG_BUILD_FOLDER_NAME} ${PKG_BIN_NAME_DEBIAN}
+
+        # Clean folder
+        - rm -Rf ${PKG_BUILD_FOLDER_NAME}
+    artifacts:
+        paths:
+            - $ARTIFACTS_FOLDER/*
+        expire_in: 10 mins
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
+
+
+.pkg_and_sign:macos:
+    stage: pkg_and_sign
+    tags:
+        - macos_signing
+    dependencies:
+        - build:version
+    script:
+        - VERSION=$(cat $VERSION_FILE)
+        - security unlock-keychain -p $SIGN_KEYCHAIN_PASSWORD $SIGN_LOGIN_KEYCHAIN_PATH
+
+        - cd $BIN_FOLDER_MACOS_PKG_AND_SIGN
+
+        # Sign excecutable
+        - codesign --force --options=runtime --entitlements ../../../Resources/macOS/Signing/entitlements.plist --sign $SIGN_DEV_ID_APP --keychain $SIGN_LOGIN_KEYCHAIN_PATH --timestamp ${BIN_NAME}
+
+        # Package and notarize the app
+        - xcrun notarytool store-credentials --apple-id $SIGN_APPLE_ID --team-id $SIGN_TEAM_ID --password $SIGN_APP_PASSWORD --keychain $SIGN_LOGIN_KEYCHAIN_PATH $SIGN_KEYCHAIN_PROFILE
+        - ditto ${BIN_NAME} ${BIN_NAME}_pkg/usr/local/bin/
+        - productbuild --identifier $SIGN_IDENTIFIER --version $VERSION --sign $SIGN_DEV_ID_INST --keychain $SIGN_LOGIN_KEYCHAIN_PATH --timestamp --root ${BIN_NAME}_pkg / ${PKG_BIN_NAME_MACOS}
+        - xcrun notarytool submit ${BIN_NAME}.pkg --keychain $SIGN_LOGIN_KEYCHAIN_PATH --keychain-profile $SIGN_KEYCHAIN_PROFILE --wait
+        - xcrun stapler staple ${BIN_NAME}.pkg
+
+        # Clean folder
+        - rm -Rf ${BIN_NAME}_pkg
+    artifacts:
+        paths:
+            - $ARTIFACTS_FOLDER/*
+        expire_in: 10 mins
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/03_stages.yml b/NodeApp/.gitlab-ci/03_stages.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c459c1651b62a43f93c894fd8b640bb8df071386
--- /dev/null
+++ b/NodeApp/.gitlab-ci/03_stages.yml
@@ -0,0 +1,7 @@
+stages:
+    - test
+    - build
+    - pkg_and_sign
+    - clean
+    - upload
+    - release
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/04_stageTest.yml b/NodeApp/.gitlab-ci/04_stageTest.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6c87377ea87becfa1b5404aae476a1cc981c85a0
--- /dev/null
+++ b/NodeApp/.gitlab-ci/04_stageTest.yml
@@ -0,0 +1,14 @@
+test:build:
+    stage: test
+    tags:
+        - build
+    image: node:latest
+    script:
+        - apt update
+        - apt install -y jq
+        - !reference [ .get_version, script ]
+
+        # Build
+        - !reference [ .build_cli, script ]
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED != "true"'
diff --git a/NodeApp/.gitlab-ci/05_stageBuild.yml b/NodeApp/.gitlab-ci/05_stageBuild.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2771ad328154f051d2b2356ce86715ff6b3e0f05
--- /dev/null
+++ b/NodeApp/.gitlab-ci/05_stageBuild.yml
@@ -0,0 +1,21 @@
+build:version:
+    stage: build
+    tags:
+        - build
+    image: node:latest
+    script:
+        - apt update
+        - apt install -y jq
+        - !reference [ .get_version, script ]
+        - mkdir -p $ARTIFACTS_FOLDER
+        - echo $VERSION > $VERSION_FILE
+
+        # Build
+        - !reference [ .build_cli, script ]
+    artifacts:
+        untracked: true
+        paths:
+            - $ARTIFACTS_FOLDER/*
+        expire_in: 10 mins
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
diff --git a/NodeApp/.gitlab-ci/06_stagePkgAndSign.yml b/NodeApp/.gitlab-ci/06_stagePkgAndSign.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dfdc2bd0004724db8d53b42484432f7d5adadead
--- /dev/null
+++ b/NodeApp/.gitlab-ci/06_stagePkgAndSign.yml
@@ -0,0 +1,14 @@
+pkg_and_sign:debian:
+    parallel:
+        matrix:
+            -   ARCH: [ "arm64", "amd64" ]
+    before_script:
+        - BIN_FOLDER_DEBIAN_PKG_AND_SIGN=$([[ $ARCH == "arm64" ]] && echo ${BIN_FOLDER_LINUX_ARM64} || echo ${BIN_FOLDER_LINUX_X64})
+    extends: .pkg_and_sign:debian
+
+
+pkg_and_sign:macos:
+    parallel:
+        matrix:
+            -   BIN_FOLDER_MACOS_PKG_AND_SIGN: [ "$BIN_FOLDER_MACOS_ARM64", "$BIN_FOLDER_MACOS_X64" ]
+    extends: .pkg_and_sign:macos
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/07_stageClean.yml b/NodeApp/.gitlab-ci/07_stageClean.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4eef3851aaa4b5b47ef46f6f3efa81e95216f059
--- /dev/null
+++ b/NodeApp/.gitlab-ci/07_stageClean.yml
@@ -0,0 +1,48 @@
+clean:release:
+    stage: clean
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [ .get_version, script ]
+        - !reference [ .clean_release, script ]
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
+
+
+clean:packages:
+    stage: clean
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [ .get_version, script ]
+        - !reference [ .clean_packages, script ]
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
+
+
+clean:dev:release:
+    stage: clean
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [ .get_version, script ]
+        - VERSION="${VERSION}${VERSION_DEV_SUFFIX}"
+        - !reference [ .clean_release, script ]
+    rules:
+        -   if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+
+
+clean:dev:packages:
+    stage: clean
+    tags:
+        - gitlab_clean
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [ .get_version, script ]
+        - VERSION="${VERSION}${VERSION_DEV_SUFFIX}"
+        - !reference [ .clean_packages, script ]
+    rules:
+        -   if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/08_stageUpload.yml b/NodeApp/.gitlab-ci/08_stageUpload.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9ebb3fdf89f0cd171cd0e878e04b9c560c2165ec
--- /dev/null
+++ b/NodeApp/.gitlab-ci/08_stageUpload.yml
@@ -0,0 +1,52 @@
+upload:packages:
+    stage: upload
+    tags:
+        - gitlab_package
+    dependencies:
+        - pkg_and_sign:macos
+        - pkg_and_sign:debian
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [ .get_version, script ]
+        - !reference [ .get_packages_url, script ]
+
+        # macOS
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_MACOS_ARM64} "${PACKAGE_URL_MACOS_ARM64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_MACOS_X64} "${PACKAGE_URL_MACOS_X64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_MACOS_ARM64} "${PACKAGE_URL_MACOS_ARM64_PKG}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_MACOS_X64} "${PACKAGE_URL_MACOS_X64_PKG}";'
+
+        # Linux
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_LINUX_ARM64} "${PACKAGE_URL_LINUX_ARM64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_LINUX_X64} "${PACKAGE_URL_LINUX_X64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_DEBIAN_ARM64} "${PACKAGE_URL_DEBIAN_ARM64_PKG}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_PKG_FILE_DEBIAN_X64} "${PACKAGE_URL_DEBIAN_X64_PKG}";'
+
+        # Windows
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_WINDOWS_ARM64} "${PACKAGE_URL_WINDOWS_ARM64_BIN}";'
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${BIN_FILE_WINDOWS_X64} "${PACKAGE_URL_WINDOWS_X64_BIN}";'
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
+
+
+upload:packages:wiki:
+    stage: upload
+    tags:
+        - gitlab_package
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        # Install dependencies
+        - apk update
+        - apk add xz
+
+        - !reference [ .get_version, script ]
+        - !reference [ .get_packages_url, script ]
+
+        # Create archive
+        - WIKI_ARCHIVE_PATH="${ARTIFACTS_FOLDER}/${WIKI_ARCHIVE_NAME}"
+        - tar -v -c -C "${CI_PROJECT_DIR}/${WIKI_FOLDER}" -J -f "${WIKI_ARCHIVE_PATH}" . # Ubuntu: tar --verbose --create --cd wiki-test-2 --xz --file file.tar.bz2
+
+        # Send package
+        - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${WIKI_ARCHIVE_PATH} "${PACKAGE_URL_WIKI}";'
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
\ No newline at end of file
diff --git a/NodeApp/.gitlab-ci/09_stageRelease.yml b/NodeApp/.gitlab-ci/09_stageRelease.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ef93e4ed4185c81107861e8ca5110368e5c6c434
--- /dev/null
+++ b/NodeApp/.gitlab-ci/09_stageRelease.yml
@@ -0,0 +1,114 @@
+release:wiki:
+    stage: release
+    tags:
+        - release
+    image: alpine:latest
+    script:
+        - !reference [ .get_version, script ]
+
+        - apk update
+        - apk add git
+
+        # Define URL for the wiki in terms of project-agnostic predefined variables
+        - WIKI_URL="${CI_SERVER_PROTOCOL}://project_${CI_PROJECT_ID}_bot:${GITLAB_PROJECT_ACCESS_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}/${CI_PROJECT_PATH}.wiki.git"
+
+        # Clone this project's wiki under /tmp
+        - rm -rf "/tmp/${CI_PROJECT_NAME}.wiki"
+        - cd /tmp
+        - git clone "${WIKI_URL}"
+
+        # Enter the cloned repo
+        - cd "${CI_PROJECT_NAME}.wiki"
+
+        # Update the file
+        - mv .git/ ../
+        - rm -rf ./*
+        - mv ../.git/ ./
+        - cp "${CI_PROJECT_DIR}/.gitignore" .
+        - cp -R "${CI_PROJECT_DIR}/${WIKI_FOLDER}/." .
+
+        # Set committer info
+        - git config user.name "$GITLAB_USER_NAME"
+        - git config user.email "$GITLAB_USER_EMAIL"
+
+        # Commit the gitignore file
+        - git add ".gitignore"
+        - git commit -m "Add gitignore file" || true
+
+        # Commit the file
+        - git add .
+        - git commit -m "${VERSION}" || true
+
+        # Push the change back to the master branch of the wiki
+        - git push origin "HEAD:main"
+    rules:
+        -   if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+
+
+release:gitlab:
+    stage: release
+    tags:
+        - release
+    image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
+    script:
+        - !reference [ .get_version, script ]
+        - !reference [ .get_packages_url, script ]
+
+        # Extract description from CHANGELOG.md
+        - CHANGELOG_LINE_START=`awk '/##\ [0-9]+\.[0-9]+\.[0-9]+/{print NR; exit;}' CHANGELOG.md`
+        - CHANGELOG_LINE_END=`awk '/##\ [0-9]+\.[0-9]+\.[0-9]+/{ count++; if(count>1) {print NR; exit;}}' CHANGELOG.md`
+        - DESCRIPTION=`awk 'NR > '$CHANGELOG_LINE_START' && NR < '$CHANGELOG_LINE_END'' CHANGELOG.md`
+
+        # Create Release (can't be done by release_step of gitlab image because it don't have access to env var defined in script_step)
+        - >
+            RELEASE_DATA=$(jq --null-input --arg version "$VERSION" --arg description "# Changelog (version $VERSION) $DESCRIPTION" --arg tag_name "$VERSION" --arg ref "$CI_COMMIT_SHORT_SHA" '{
+                "name": $version,
+                "description": $description,
+                "tag_name": $tag_name,
+                "ref": $ref,
+                "assets": {
+                    "links": [
+                        {
+                          "name": "Windows (ARM64) binary",
+                          "url": "'${PACKAGE_URL_WINDOWS_ARM64_BIN}'",
+                        },{
+                            "name": "Windows (x64) binary",
+                            "url": "'${PACKAGE_URL_WINDOWS_X64_BIN}'",
+                        },{
+                            "name": "Linux (ARM64) binary",
+                            "url": "'${PACKAGE_URL_LINUX_ARM64_BIN}'",
+                        },{
+                            "name": "Linux (x64) binary",
+                            "url": "'${PACKAGE_URL_LINUX_X64_BIN}'",
+                        },{
+                            "name": "Debian / Ubuntu (ARM64) package",
+                            "url": "'${PACKAGE_URL_DEBIAN_ARM64_PKG}'",
+                        },{
+                            "name": "Debian / Ubuntu (x64) package",
+                            "url": "'${PACKAGE_URL_DEBIAN_X64_PKG}'",
+                        },{
+                            "name": "macOS (Intel) binary",
+                            "url": "'${PACKAGE_URL_MACOS_X64_BIN}'",
+                        },{
+                          "name": "macOS (Apple Silicon) binary",
+                          "url": "'${PACKAGE_URL_MACOS_ARM64_BIN}'",
+                        },{
+                            "name": "macOS (Intel) package",
+                            "url": "'${PACKAGE_URL_MACOS_X64_PKG}'",
+                        },{
+                            "name": "macOS (Apple Silicon) package",
+                            "url": "'${PACKAGE_URL_MACOS_ARM64_PKG}'",
+                        },{
+                          "name": "Wiki",
+                          "url": "'${PACKAGE_URL_WIKI}'",
+                        }
+                    ]                       
+                }
+            }')
+        - >
+            curl --data "${RELEASE_DATA}" \
+              --header "Content-Type: application/json" \
+              --header "JOB-TOKEN: $CI_JOB_TOKEN" \
+              --request POST "${GITLAB_API_PROJECT_URL}/releases"
+    rules:
+        -   if: '$CI_COMMIT_REF_PROTECTED == "true"'
\ No newline at end of file
diff --git a/NodeApp/.idea/DojoCLI.iml b/NodeApp/.idea/DojoCLI.iml
index 24643cc37449b4bde54411a80b8ed61258225e34..d47865a1c8d932c244bdb1f09d5eb3295d5dc715 100644
--- a/NodeApp/.idea/DojoCLI.iml
+++ b/NodeApp/.idea/DojoCLI.iml
@@ -6,6 +6,9 @@
       <excludeFolder url="file://$MODULE_DIR$/temp" />
       <excludeFolder url="file://$MODULE_DIR$/tmp" />
     </content>
+    <content url="file://$MODULE_DIR$/.gitlab-ci-local">
+      <excludeFolder url="file://$MODULE_DIR$/.gitlab-ci-local" />
+    </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
diff --git a/NodeApp/package-lock.json b/NodeApp/package-lock.json
index 6b5fe0f904508e058062b4ebf9303340638b61a5..6d9c32798aafb2306f209eb808b9ce5398711637 100644
--- a/NodeApp/package-lock.json
+++ b/NodeApp/package-lock.json
@@ -1,12 +1,12 @@
 {
     "name": "dojo_cli",
-    "version": "1.0.1",
+    "version": "2.1.0",
     "lockfileVersion": 3,
     "requires": true,
     "packages": {
         "": {
             "name": "dojo_cli",
-            "version": "1.0.1",
+            "version": "2.1.0",
             "dependencies": {
                 "ajv": "^8.12.0",
                 "appdata-path": "^1.0.0",
@@ -33,6 +33,7 @@
                 "@types/jsonwebtoken": "^8.5.9",
                 "@types/node": "^18.17.2",
                 "@types/tar-stream": "^2.2.2",
+                "dotenv-vault": "^1.25.0",
                 "pkg": "^5.8.1",
                 "tiny-typed-emitter": "^2.1.0",
                 "ts-node": "^10.9.1",
@@ -226,6 +227,432 @@
                 "node": ">= 8"
             }
         },
+        "node_modules/@oclif/core": {
+            "version": "1.26.2",
+            "resolved": "https://registry.npmjs.org/@oclif/core/-/core-1.26.2.tgz",
+            "integrity": "sha512-6jYuZgXvHfOIc9GIaS4T3CIKGTjPmfAxuMcbCbMRKJJl4aq/4xeRlEz0E8/hz8HxvxZBGvN2GwAUHlrGWQVrVw==",
+            "dev": true,
+            "dependencies": {
+                "@oclif/linewrap": "^1.0.0",
+                "@oclif/screen": "^3.0.4",
+                "ansi-escapes": "^4.3.2",
+                "ansi-styles": "^4.3.0",
+                "cardinal": "^2.1.1",
+                "chalk": "^4.1.2",
+                "clean-stack": "^3.0.1",
+                "cli-progress": "^3.10.0",
+                "debug": "^4.3.4",
+                "ejs": "^3.1.6",
+                "fs-extra": "^9.1.0",
+                "get-package-type": "^0.1.0",
+                "globby": "^11.1.0",
+                "hyperlinker": "^1.0.0",
+                "indent-string": "^4.0.0",
+                "is-wsl": "^2.2.0",
+                "js-yaml": "^3.14.1",
+                "natural-orderby": "^2.0.3",
+                "object-treeify": "^1.1.33",
+                "password-prompt": "^1.1.2",
+                "semver": "^7.3.7",
+                "string-width": "^4.2.3",
+                "strip-ansi": "^6.0.1",
+                "supports-color": "^8.1.1",
+                "supports-hyperlinks": "^2.2.0",
+                "tslib": "^2.4.1",
+                "widest-line": "^3.1.0",
+                "wrap-ansi": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@oclif/core/node_modules/fs-extra": {
+            "version": "9.1.0",
+            "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+            "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+            "dev": true,
+            "dependencies": {
+                "at-least-node": "^1.0.0",
+                "graceful-fs": "^4.2.0",
+                "jsonfile": "^6.0.1",
+                "universalify": "^2.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@oclif/core/node_modules/semver": {
+            "version": "7.5.4",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+            "dev": true,
+            "dependencies": {
+                "lru-cache": "^6.0.0"
+            },
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@oclif/core/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/@oclif/linewrap": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/@oclif/linewrap/-/linewrap-1.0.0.tgz",
+            "integrity": "sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw==",
+            "dev": true
+        },
+        "node_modules/@oclif/plugin-help": {
+            "version": "5.2.19",
+            "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-5.2.19.tgz",
+            "integrity": "sha512-gf6/dFtzMJ8RA4ovlBCBGJsZsd4jPXhYWJho+Gh6KmA+Ev9LupoExbE0qT+a2uHJyHEvIg4uX/MBW3qdERD/8g==",
+            "dev": true,
+            "dependencies": {
+                "@oclif/core": "^2.15.0"
+            },
+            "engines": {
+                "node": ">=12.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-help/node_modules/@oclif/core": {
+            "version": "2.15.0",
+            "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.15.0.tgz",
+            "integrity": "sha512-fNEMG5DzJHhYmI3MgpByTvltBOMyFcnRIUMxbiz2ai8rhaYgaTHMG3Q38HcosfIvtw9nCjxpcQtC8MN8QtVCcA==",
+            "dev": true,
+            "dependencies": {
+                "@types/cli-progress": "^3.11.0",
+                "ansi-escapes": "^4.3.2",
+                "ansi-styles": "^4.3.0",
+                "cardinal": "^2.1.1",
+                "chalk": "^4.1.2",
+                "clean-stack": "^3.0.1",
+                "cli-progress": "^3.12.0",
+                "debug": "^4.3.4",
+                "ejs": "^3.1.8",
+                "get-package-type": "^0.1.0",
+                "globby": "^11.1.0",
+                "hyperlinker": "^1.0.0",
+                "indent-string": "^4.0.0",
+                "is-wsl": "^2.2.0",
+                "js-yaml": "^3.14.1",
+                "natural-orderby": "^2.0.3",
+                "object-treeify": "^1.1.33",
+                "password-prompt": "^1.1.2",
+                "slice-ansi": "^4.0.0",
+                "string-width": "^4.2.3",
+                "strip-ansi": "^6.0.1",
+                "supports-color": "^8.1.1",
+                "supports-hyperlinks": "^2.2.0",
+                "ts-node": "^10.9.1",
+                "tslib": "^2.5.0",
+                "widest-line": "^3.1.0",
+                "wordwrap": "^1.0.0",
+                "wrap-ansi": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-help/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/@oclif/plugin-not-found": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-2.4.1.tgz",
+            "integrity": "sha512-LqW7qpw5Q8ploRiup2jEIMQJXcxHP1tpwj45GApKQMe7GRdGdRdjBT9Tu+U2tdEgMqgMplAIhOsYCx2nc2nMSw==",
+            "dev": true,
+            "dependencies": {
+                "@oclif/core": "^2.15.0",
+                "chalk": "^4",
+                "fast-levenshtein": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=12.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-not-found/node_modules/@oclif/core": {
+            "version": "2.15.0",
+            "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.15.0.tgz",
+            "integrity": "sha512-fNEMG5DzJHhYmI3MgpByTvltBOMyFcnRIUMxbiz2ai8rhaYgaTHMG3Q38HcosfIvtw9nCjxpcQtC8MN8QtVCcA==",
+            "dev": true,
+            "dependencies": {
+                "@types/cli-progress": "^3.11.0",
+                "ansi-escapes": "^4.3.2",
+                "ansi-styles": "^4.3.0",
+                "cardinal": "^2.1.1",
+                "chalk": "^4.1.2",
+                "clean-stack": "^3.0.1",
+                "cli-progress": "^3.12.0",
+                "debug": "^4.3.4",
+                "ejs": "^3.1.8",
+                "get-package-type": "^0.1.0",
+                "globby": "^11.1.0",
+                "hyperlinker": "^1.0.0",
+                "indent-string": "^4.0.0",
+                "is-wsl": "^2.2.0",
+                "js-yaml": "^3.14.1",
+                "natural-orderby": "^2.0.3",
+                "object-treeify": "^1.1.33",
+                "password-prompt": "^1.1.2",
+                "slice-ansi": "^4.0.0",
+                "string-width": "^4.2.3",
+                "strip-ansi": "^6.0.1",
+                "supports-color": "^8.1.1",
+                "supports-hyperlinks": "^2.2.0",
+                "ts-node": "^10.9.1",
+                "tslib": "^2.5.0",
+                "widest-line": "^3.1.0",
+                "wordwrap": "^1.0.0",
+                "wrap-ansi": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-not-found/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/@oclif/plugin-update": {
+            "version": "3.2.3",
+            "resolved": "https://registry.npmjs.org/@oclif/plugin-update/-/plugin-update-3.2.3.tgz",
+            "integrity": "sha512-JVKwp4ysG9GU4RmG59MZYMunz8onRI+wEQzJThyYkUFd0VfZviYt2FHsyoNtxi30l0tInC8APgKp1pCCO4e+FQ==",
+            "dev": true,
+            "dependencies": {
+                "@oclif/core": "^2.11.8",
+                "chalk": "^4",
+                "cross-spawn": "^7.0.3",
+                "debug": "^4.3.1",
+                "filesize": "^6.1.0",
+                "fs-extra": "^9.0.1",
+                "http-call": "^5.3.0",
+                "inquirer": "^8.2.6",
+                "lodash.throttle": "^4.1.1",
+                "log-chopper": "^1.0.2",
+                "semver": "^7.5.4",
+                "tar-fs": "^2.1.1"
+            },
+            "engines": {
+                "node": ">=12.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-update/node_modules/@oclif/core": {
+            "version": "2.15.0",
+            "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.15.0.tgz",
+            "integrity": "sha512-fNEMG5DzJHhYmI3MgpByTvltBOMyFcnRIUMxbiz2ai8rhaYgaTHMG3Q38HcosfIvtw9nCjxpcQtC8MN8QtVCcA==",
+            "dev": true,
+            "dependencies": {
+                "@types/cli-progress": "^3.11.0",
+                "ansi-escapes": "^4.3.2",
+                "ansi-styles": "^4.3.0",
+                "cardinal": "^2.1.1",
+                "chalk": "^4.1.2",
+                "clean-stack": "^3.0.1",
+                "cli-progress": "^3.12.0",
+                "debug": "^4.3.4",
+                "ejs": "^3.1.8",
+                "get-package-type": "^0.1.0",
+                "globby": "^11.1.0",
+                "hyperlinker": "^1.0.0",
+                "indent-string": "^4.0.0",
+                "is-wsl": "^2.2.0",
+                "js-yaml": "^3.14.1",
+                "natural-orderby": "^2.0.3",
+                "object-treeify": "^1.1.33",
+                "password-prompt": "^1.1.2",
+                "slice-ansi": "^4.0.0",
+                "string-width": "^4.2.3",
+                "strip-ansi": "^6.0.1",
+                "supports-color": "^8.1.1",
+                "supports-hyperlinks": "^2.2.0",
+                "ts-node": "^10.9.1",
+                "tslib": "^2.5.0",
+                "widest-line": "^3.1.0",
+                "wordwrap": "^1.0.0",
+                "wrap-ansi": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-update/node_modules/fs-extra": {
+            "version": "9.1.0",
+            "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+            "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+            "dev": true,
+            "dependencies": {
+                "at-least-node": "^1.0.0",
+                "graceful-fs": "^4.2.0",
+                "jsonfile": "^6.0.1",
+                "universalify": "^2.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@oclif/plugin-update/node_modules/semver": {
+            "version": "7.5.4",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+            "dev": true,
+            "dependencies": {
+                "lru-cache": "^6.0.0"
+            },
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@oclif/plugin-update/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/@oclif/plugin-warn-if-update-available": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-2.1.0.tgz",
+            "integrity": "sha512-liTWd/qSIqALsikr88CAB9o2xGFt0LdT5REbhxtrx16/trRmkxQ+0RHK1FieGZAzEENx/4D3YcC/Y67a0uyO0g==",
+            "dev": true,
+            "dependencies": {
+                "@oclif/core": "^2.15.0",
+                "chalk": "^4.1.0",
+                "debug": "^4.1.0",
+                "http-call": "^5.2.2",
+                "lodash.template": "^4.5.0",
+                "semver": "^7.5.4"
+            },
+            "engines": {
+                "node": ">=12.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-warn-if-update-available/node_modules/@oclif/core": {
+            "version": "2.15.0",
+            "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.15.0.tgz",
+            "integrity": "sha512-fNEMG5DzJHhYmI3MgpByTvltBOMyFcnRIUMxbiz2ai8rhaYgaTHMG3Q38HcosfIvtw9nCjxpcQtC8MN8QtVCcA==",
+            "dev": true,
+            "dependencies": {
+                "@types/cli-progress": "^3.11.0",
+                "ansi-escapes": "^4.3.2",
+                "ansi-styles": "^4.3.0",
+                "cardinal": "^2.1.1",
+                "chalk": "^4.1.2",
+                "clean-stack": "^3.0.1",
+                "cli-progress": "^3.12.0",
+                "debug": "^4.3.4",
+                "ejs": "^3.1.8",
+                "get-package-type": "^0.1.0",
+                "globby": "^11.1.0",
+                "hyperlinker": "^1.0.0",
+                "indent-string": "^4.0.0",
+                "is-wsl": "^2.2.0",
+                "js-yaml": "^3.14.1",
+                "natural-orderby": "^2.0.3",
+                "object-treeify": "^1.1.33",
+                "password-prompt": "^1.1.2",
+                "slice-ansi": "^4.0.0",
+                "string-width": "^4.2.3",
+                "strip-ansi": "^6.0.1",
+                "supports-color": "^8.1.1",
+                "supports-hyperlinks": "^2.2.0",
+                "ts-node": "^10.9.1",
+                "tslib": "^2.5.0",
+                "widest-line": "^3.1.0",
+                "wordwrap": "^1.0.0",
+                "wrap-ansi": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@oclif/plugin-warn-if-update-available/node_modules/semver": {
+            "version": "7.5.4",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+            "dev": true,
+            "dependencies": {
+                "lru-cache": "^6.0.0"
+            },
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/@oclif/plugin-warn-if-update-available/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/@oclif/screen": {
+            "version": "3.0.6",
+            "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.6.tgz",
+            "integrity": "sha512-nEv7dFPxCrWrvK6dQ8zya0/Kb54EXVcwIKV9capjSa89ZDoOo+qH0YSo4/eQVECXgW3eUvgKLDIcIt62YBk0HA==",
+            "dev": true,
+            "engines": {
+                "node": ">=12.0.0"
+            }
+        },
         "node_modules/@tsconfig/node10": {
             "version": "1.0.9",
             "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
@@ -250,6 +677,15 @@
             "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
             "dev": true
         },
+        "node_modules/@types/cli-progress": {
+            "version": "3.11.2",
+            "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.2.tgz",
+            "integrity": "sha512-Yt/8rEJalfa9ve2SbfQnwFHrc9QF52JIZYHW3FDaTMpkCvnns26ueKiPHDxyJ0CS//IqjMINTx7R5Xa7k7uFHQ==",
+            "dev": true,
+            "dependencies": {
+                "@types/node": "*"
+            }
+        },
         "node_modules/@types/fs-extra": {
             "version": "11.0.1",
             "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz",
@@ -409,6 +845,12 @@
                 "url": "https://github.com/chalk/ansi-styles?sponsor=1"
             }
         },
+        "node_modules/ansicolors": {
+            "version": "0.3.2",
+            "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
+            "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
+            "dev": true
+        },
         "node_modules/appdata-path": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/appdata-path/-/appdata-path-1.0.0.tgz",
@@ -420,6 +862,15 @@
             "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
             "dev": true
         },
+        "node_modules/argparse": {
+            "version": "1.0.10",
+            "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+            "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+            "dev": true,
+            "dependencies": {
+                "sprintf-js": "~1.0.2"
+            }
+        },
         "node_modules/array-union": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -429,6 +880,15 @@
                 "node": ">=8"
             }
         },
+        "node_modules/astral-regex": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+            "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+            "dev": true,
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/async": {
             "version": "3.2.4",
             "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
@@ -463,6 +923,12 @@
             "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz",
             "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw=="
         },
+        "node_modules/balanced-match": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+            "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+            "dev": true
+        },
         "node_modules/base64-js": {
             "version": "1.5.1",
             "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -524,6 +990,16 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/brace-expansion": {
+            "version": "1.1.11",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+            "dev": true,
+            "dependencies": {
+                "balanced-match": "^1.0.0",
+                "concat-map": "0.0.1"
+            }
+        },
         "node_modules/braces": {
             "version": "3.0.2",
             "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
@@ -564,6 +1040,15 @@
             "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
             "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
         },
+        "node_modules/byline": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
+            "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==",
+            "dev": true,
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/camelcase": {
             "version": "6.3.0",
             "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
@@ -575,6 +1060,19 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/cardinal": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
+            "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==",
+            "dev": true,
+            "dependencies": {
+                "ansicolors": "~0.3.2",
+                "redeyed": "~2.1.0"
+            },
+            "bin": {
+                "cdl": "bin/cdl.js"
+            }
+        },
         "node_modules/chalk": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -601,6 +1099,33 @@
             "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
             "dev": true
         },
+        "node_modules/clean-stack": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz",
+            "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==",
+            "dev": true,
+            "dependencies": {
+                "escape-string-regexp": "4.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/clean-stack/node_modules/escape-string-regexp": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+            "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+            "dev": true,
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
         "node_modules/cli-boxes": {
             "version": "2.2.1",
             "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
@@ -623,6 +1148,18 @@
                 "node": ">=8"
             }
         },
+        "node_modules/cli-progress": {
+            "version": "3.12.0",
+            "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz",
+            "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==",
+            "dev": true,
+            "dependencies": {
+                "string-width": "^4.2.3"
+            },
+            "engines": {
+                "node": ">=4"
+            }
+        },
         "node_modules/cli-spinners": {
             "version": "2.9.0",
             "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz",
@@ -736,6 +1273,21 @@
                 "node": ">=16"
             }
         },
+        "node_modules/concat-map": {
+            "version": "0.0.1",
+            "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+            "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+            "dev": true
+        },
+        "node_modules/content-type": {
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+            "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+            "dev": true,
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
         "node_modules/core-util-is": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -748,6 +1300,20 @@
             "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
             "dev": true
         },
+        "node_modules/cross-spawn": {
+            "version": "7.0.3",
+            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+            "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+            "dev": true,
+            "dependencies": {
+                "path-key": "^3.1.0",
+                "shebang-command": "^2.0.0",
+                "which": "^2.0.1"
+            },
+            "engines": {
+                "node": ">= 8"
+            }
+        },
         "node_modules/debug": {
             "version": "4.3.4",
             "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -855,6 +1421,38 @@
                 "url": "https://github.com/motdotla/dotenv?sponsor=1"
             }
         },
+        "node_modules/dotenv-vault": {
+            "version": "1.25.0",
+            "resolved": "https://registry.npmjs.org/dotenv-vault/-/dotenv-vault-1.25.0.tgz",
+            "integrity": "sha512-+3isN+iq0E5VE+pfluBcNYb2qFf/Zu5q44Neh3Bazl82vk86xdUbI2z2cYHgJq5bMgRW1kUOaGWsgXjYlGUhng==",
+            "dev": true,
+            "dependencies": {
+                "@oclif/core": "^1",
+                "@oclif/plugin-help": "^5.2.11",
+                "@oclif/plugin-not-found": "^2.3.24",
+                "@oclif/plugin-update": "^3.1.16",
+                "@oclif/plugin-warn-if-update-available": "^2.0.40",
+                "axios": "^0.27.2",
+                "chalk": "^4.1.2",
+                "dotenv": "^16.3.1"
+            },
+            "bin": {
+                "dotenv-vault": "bin/run"
+            },
+            "engines": {
+                "node": ">=16"
+            }
+        },
+        "node_modules/dotenv-vault/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==",
+            "dev": true,
+            "dependencies": {
+                "follow-redirects": "^1.14.9",
+                "form-data": "^4.0.0"
+            }
+        },
         "node_modules/ecdsa-sig-formatter": {
             "version": "1.0.11",
             "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@@ -863,6 +1461,21 @@
                 "safe-buffer": "^5.0.1"
             }
         },
+        "node_modules/ejs": {
+            "version": "3.1.9",
+            "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
+            "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==",
+            "dev": true,
+            "dependencies": {
+                "jake": "^10.8.5"
+            },
+            "bin": {
+                "ejs": "bin/cli.js"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/emoji-regex": {
             "version": "8.0.0",
             "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -882,6 +1495,21 @@
                 "once": "^1.4.0"
             }
         },
+        "node_modules/error-ex": {
+            "version": "1.3.2",
+            "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+            "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+            "dev": true,
+            "dependencies": {
+                "is-arrayish": "^0.2.1"
+            }
+        },
+        "node_modules/error-ex/node_modules/is-arrayish": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+            "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+            "dev": true
+        },
         "node_modules/escalade": {
             "version": "3.1.1",
             "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -899,6 +1527,19 @@
                 "node": ">=0.8.0"
             }
         },
+        "node_modules/esprima": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+            "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+            "dev": true,
+            "bin": {
+                "esparse": "bin/esparse.js",
+                "esvalidate": "bin/esvalidate.js"
+            },
+            "engines": {
+                "node": ">=4"
+            }
+        },
         "node_modules/expand-template": {
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
@@ -947,6 +1588,24 @@
                 "node": ">=8.6.0"
             }
         },
+        "node_modules/fast-levenshtein": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz",
+            "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==",
+            "dev": true,
+            "dependencies": {
+                "fastest-levenshtein": "^1.0.7"
+            }
+        },
+        "node_modules/fastest-levenshtein": {
+            "version": "1.0.16",
+            "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+            "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+            "dev": true,
+            "engines": {
+                "node": ">= 4.9.1"
+            }
+        },
         "node_modules/fastq": {
             "version": "1.15.0",
             "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
@@ -975,6 +1634,45 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/filelist": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
+            "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+            "dev": true,
+            "dependencies": {
+                "minimatch": "^5.0.1"
+            }
+        },
+        "node_modules/filelist/node_modules/brace-expansion": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+            "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+            "dev": true,
+            "dependencies": {
+                "balanced-match": "^1.0.0"
+            }
+        },
+        "node_modules/filelist/node_modules/minimatch": {
+            "version": "5.1.6",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+            "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+            "dev": true,
+            "dependencies": {
+                "brace-expansion": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/filesize": {
+            "version": "6.4.0",
+            "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz",
+            "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==",
+            "dev": true,
+            "engines": {
+                "node": ">= 0.4.0"
+            }
+        },
         "node_modules/fill-range": {
             "version": "7.0.1",
             "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -1098,6 +1796,15 @@
                 "node": "6.* || 8.* || >= 10.*"
             }
         },
+        "node_modules/get-package-type": {
+            "version": "0.1.0",
+            "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+            "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+            "dev": true,
+            "engines": {
+                "node": ">=8.0.0"
+            }
+        },
         "node_modules/github-from-package": {
             "version": "0.0.0",
             "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
@@ -1161,6 +1868,23 @@
                 "node": ">=8"
             }
         },
+        "node_modules/http-call": {
+            "version": "5.3.0",
+            "resolved": "https://registry.npmjs.org/http-call/-/http-call-5.3.0.tgz",
+            "integrity": "sha512-ahwimsC23ICE4kPl9xTBjKB4inbRaeLyZeRunC/1Jy/Z6X8tv22MEAjK+KBOMSVLaqXPTTmd8638waVIKLGx2w==",
+            "dev": true,
+            "dependencies": {
+                "content-type": "^1.0.4",
+                "debug": "^4.1.1",
+                "is-retry-allowed": "^1.1.0",
+                "is-stream": "^2.0.0",
+                "parse-json": "^4.0.0",
+                "tunnel-agent": "^0.6.0"
+            },
+            "engines": {
+                "node": ">=8.0.0"
+            }
+        },
         "node_modules/http-status-codes": {
             "version": "2.2.0",
             "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.2.0.tgz",
@@ -1179,6 +1903,15 @@
                 "node": ">= 6"
             }
         },
+        "node_modules/hyperlinker": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz",
+            "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==",
+            "dev": true,
+            "engines": {
+                "node": ">=4"
+            }
+        },
         "node_modules/iconv-lite": {
             "version": "0.4.24",
             "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -1218,6 +1951,15 @@
                 "node": ">= 4"
             }
         },
+        "node_modules/indent-string": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+            "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+            "dev": true,
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/inherits": {
             "version": "2.0.4",
             "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -1230,9 +1972,9 @@
             "dev": true
         },
         "node_modules/inquirer": {
-            "version": "8.2.5",
-            "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
-            "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
+            "version": "8.2.6",
+            "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
+            "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
             "dependencies": {
                 "ansi-escapes": "^4.2.1",
                 "chalk": "^4.1.1",
@@ -1248,12 +1990,25 @@
                 "string-width": "^4.1.0",
                 "strip-ansi": "^6.0.0",
                 "through": "^2.3.6",
-                "wrap-ansi": "^7.0.0"
+                "wrap-ansi": "^6.0.1"
             },
             "engines": {
                 "node": ">=12.0.0"
             }
         },
+        "node_modules/inquirer/node_modules/wrap-ansi": {
+            "version": "6.2.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+            "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+            "dependencies": {
+                "ansi-styles": "^4.0.0",
+                "string-width": "^4.1.0",
+                "strip-ansi": "^6.0.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/into-stream": {
             "version": "6.0.0",
             "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz",
@@ -1287,6 +2042,21 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
+        "node_modules/is-docker": {
+            "version": "2.2.1",
+            "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+            "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+            "dev": true,
+            "bin": {
+                "is-docker": "cli.js"
+            },
+            "engines": {
+                "node": ">=8"
+            },
+            "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",
@@ -1333,6 +2103,15 @@
                 "node": ">=0.12.0"
             }
         },
+        "node_modules/is-retry-allowed": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
+            "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
+            "dev": true,
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
         "node_modules/is-stream": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -1355,12 +2134,61 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/is-wsl": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+            "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+            "dev": true,
+            "dependencies": {
+                "is-docker": "^2.0.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/isarray": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
             "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
             "dev": true
         },
+        "node_modules/isexe": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+            "dev": true
+        },
+        "node_modules/jake": {
+            "version": "10.8.7",
+            "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
+            "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
+            "dev": true,
+            "dependencies": {
+                "async": "^3.2.3",
+                "chalk": "^4.0.2",
+                "filelist": "^1.0.4",
+                "minimatch": "^3.1.2"
+            },
+            "bin": {
+                "jake": "bin/cli.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/js-yaml": {
+            "version": "3.14.1",
+            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+            "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+            "dev": true,
+            "dependencies": {
+                "argparse": "^1.0.7",
+                "esprima": "^4.0.0"
+            },
+            "bin": {
+                "js-yaml": "bin/js-yaml.js"
+            }
+        },
         "node_modules/jsesc": {
             "version": "2.5.2",
             "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -1373,6 +2201,12 @@
                 "node": ">=4"
             }
         },
+        "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==",
+            "dev": true
+        },
         "node_modules/json-schema-traverse": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
@@ -1450,6 +2284,12 @@
             "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
             "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
         },
+        "node_modules/lodash._reinterpolate": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+            "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
+            "dev": true
+        },
         "node_modules/lodash.includes": {
             "version": "4.3.0",
             "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
@@ -1485,6 +2325,43 @@
             "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
             "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
         },
+        "node_modules/lodash.template": {
+            "version": "4.5.0",
+            "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
+            "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
+            "dev": true,
+            "dependencies": {
+                "lodash._reinterpolate": "^3.0.0",
+                "lodash.templatesettings": "^4.0.0"
+            }
+        },
+        "node_modules/lodash.templatesettings": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
+            "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
+            "dev": true,
+            "dependencies": {
+                "lodash._reinterpolate": "^3.0.0"
+            }
+        },
+        "node_modules/lodash.throttle": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+            "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
+            "dev": true
+        },
+        "node_modules/log-chopper": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/log-chopper/-/log-chopper-1.0.2.tgz",
+            "integrity": "sha512-tEWS6Fb+Xv0yLChJ6saA1DP3H1yPL0PfiIN7SDJ+U/CyP+fD4G/dhKfow+P5UuJWi6BdE4mUcPkJclGXCWxDrg==",
+            "dev": true,
+            "dependencies": {
+                "byline": "5.x"
+            },
+            "engines": {
+                "node": ">=6.0.0"
+            }
+        },
         "node_modules/log-symbols": {
             "version": "4.1.0",
             "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -1592,6 +2469,18 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/minimatch": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+            "dev": true,
+            "dependencies": {
+                "brace-expansion": "^1.1.7"
+            },
+            "engines": {
+                "node": "*"
+            }
+        },
         "node_modules/minimist": {
             "version": "1.2.8",
             "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
@@ -1647,6 +2536,15 @@
             "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
             "dev": true
         },
+        "node_modules/natural-orderby": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz",
+            "integrity": "sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==",
+            "dev": true,
+            "engines": {
+                "node": "*"
+            }
+        },
         "node_modules/node-abi": {
             "version": "3.45.0",
             "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz",
@@ -1694,6 +2592,15 @@
                 }
             }
         },
+        "node_modules/object-treeify": {
+            "version": "1.1.33",
+            "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz",
+            "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==",
+            "dev": true,
+            "engines": {
+                "node": ">= 10"
+            }
+        },
         "node_modules/once": {
             "version": "1.4.0",
             "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -1764,6 +2671,38 @@
                 "node": ">=8"
             }
         },
+        "node_modules/parse-json": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+            "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+            "dev": true,
+            "dependencies": {
+                "error-ex": "^1.3.1",
+                "json-parse-better-errors": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=4"
+            }
+        },
+        "node_modules/password-prompt": {
+            "version": "1.1.3",
+            "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.3.tgz",
+            "integrity": "sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==",
+            "dev": true,
+            "dependencies": {
+                "ansi-escapes": "^4.3.2",
+                "cross-spawn": "^7.0.3"
+            }
+        },
+        "node_modules/path-key": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+            "dev": true,
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/path-parse": {
             "version": "1.0.7",
             "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
@@ -2005,6 +2944,15 @@
                 "node": ">= 6"
             }
         },
+        "node_modules/redeyed": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz",
+            "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==",
+            "dev": true,
+            "dependencies": {
+                "esprima": "~4.0.0"
+            }
+        },
         "node_modules/require-directory": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -2152,6 +3100,27 @@
                 "semver": "bin/semver"
             }
         },
+        "node_modules/shebang-command": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+            "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+            "dev": true,
+            "dependencies": {
+                "shebang-regex": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/shebang-regex": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+            "dev": true,
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/signal-exit": {
             "version": "3.0.7",
             "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -2219,6 +3188,29 @@
                 "node": ">=8"
             }
         },
+        "node_modules/slice-ansi": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+            "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+            "dev": true,
+            "dependencies": {
+                "ansi-styles": "^4.0.0",
+                "astral-regex": "^2.0.0",
+                "is-fullwidth-code-point": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+            }
+        },
+        "node_modules/sprintf-js": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+            "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+            "dev": true
+        },
         "node_modules/stack-trace": {
             "version": "0.0.10",
             "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
@@ -2327,6 +3319,19 @@
                 "node": ">=8"
             }
         },
+        "node_modules/supports-hyperlinks": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz",
+            "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==",
+            "dev": true,
+            "dependencies": {
+                "has-flag": "^4.0.0",
+                "supports-color": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/supports-preserve-symlinks-flag": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
@@ -2574,6 +3579,21 @@
                 "webidl-conversions": "^3.0.0"
             }
         },
+        "node_modules/which": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+            "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+            "dev": true,
+            "dependencies": {
+                "isexe": "^2.0.0"
+            },
+            "bin": {
+                "node-which": "bin/node-which"
+            },
+            "engines": {
+                "node": ">= 8"
+            }
+        },
         "node_modules/widest-line": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
@@ -2619,6 +3639,12 @@
                 "node": ">= 6.4.0"
             }
         },
+        "node_modules/wordwrap": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+            "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+            "dev": true
+        },
         "node_modules/wrap-ansi": {
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
diff --git a/NodeApp/package.json b/NodeApp/package.json
index eb095058924ef551b7734599bd77cf4621dca7de..8f1ea6b3241f7a2cf8854af300f796178bce933c 100644
--- a/NodeApp/package.json
+++ b/NodeApp/package.json
@@ -1,6 +1,6 @@
 {
     "name"           : "dojo_cli",
-    "version"        : "2.0.0",
+    "version"        : "2.1.0",
     "main"           : "dist/app.js",
     "bin"            : {
         "dojo": "./dist/app.js"
@@ -17,6 +17,7 @@
             "node18-macos-x64",
             "node18-linux-arm64",
             "node18-linux-x64",
+            "node18-win-arm64",
             "node18-win-x86"
         ]
     },
@@ -48,6 +49,7 @@
         "@types/jsonwebtoken": "^8.5.9",
         "@types/node"        : "^18.17.2",
         "@types/tar-stream"  : "^2.2.2",
+        "dotenv-vault"       : "^1.25.0",
         "pkg"                : "^5.8.1",
         "tiny-typed-emitter" : "^2.1.0",
         "ts-node"            : "^10.9.1",
diff --git a/NodeApp/src/app.ts b/NodeApp/src/app.ts
index 543bc0594fc11b97e98fa5bb50265662b27bf65d..ea7d4ef9a1c6eb8f15517b3df0a0bb2cf56a6dbd 100644
--- a/NodeApp/src/app.ts
+++ b/NodeApp/src/app.ts
@@ -1,7 +1,10 @@
 // Read from the .env file
 // ATTENTION : This lines MUST be the first of this file (except for the path import)
 const path = require('node:path');
-require('dotenv').config({ path: path.join(__dirname, '../.env') });
+require('dotenv').config({
+                             path      : path.join(__dirname, '../.env'),
+                             DOTENV_KEY: 'dotenv://:key_fc323d8e0a02349342f1c6a119bb38495958ce3a43a87d19a3f674b7e2896dcb@dotenv.local/vault/.env.vault?environment=development'
+                         });
 require('./shared/helpers/TypeScriptExtensions'); // ATTENTION : This line MUST be the second of this file
 
 
diff --git a/NodeApp/src/commander/CommanderApp.ts b/NodeApp/src/commander/CommanderApp.ts
index a6002b0a382a5b6d9f54f5825dfa21b7235f7549..91ba8fe932cea2e6085cf4ff554d030589cf7771 100644
--- a/NodeApp/src/commander/CommanderApp.ts
+++ b/NodeApp/src/commander/CommanderApp.ts
@@ -12,7 +12,7 @@ class CommanderApp {
         this.program
         .name('dojo')
         .description('CLI of the Dojo application')
-        .version('2.0.0')
+        .version('{{VERSION}}')
         .showHelpAfterError()
         .configureHelp({
                            showGlobalOptions: true,
diff --git a/NodeApp/src/commander/exercise/ExerciseRunCommand.ts b/NodeApp/src/commander/exercise/ExerciseRunCommand.ts
index 7fdd21b620679f37d5919171a3ae6c1e5320ce33..9eb4d8da5a2ec909018a15e052142adc6bcacf09 100644
--- a/NodeApp/src/commander/exercise/ExerciseRunCommand.ts
+++ b/NodeApp/src/commander/exercise/ExerciseRunCommand.ts
@@ -86,7 +86,7 @@ class ExerciseRunCommand extends CommanderCommand {
                 spinner.succeed(`The exercise folder contains all the needed files`);
             }
 
-            // dojo.assignment validity
+            // dojo_assignment.json validity
             {
                 const spinner: ora.Ora = ora({
                                                  text  : `Checking ${ Config.assignment.filename } file`,
diff --git a/Resources/Debian/pkg/DEBIAN/changelog b/Resources/Debian/pkg/DEBIAN/changelog
new file mode 100644
index 0000000000000000000000000000000000000000..1203451e322bd3645b1c54f5481127e52d3375af
--- /dev/null
+++ b/Resources/Debian/pkg/DEBIAN/changelog
@@ -0,0 +1,5 @@
+{{BIN_NAME}} ({{VERSION}}) {{STABILITY}}; urgency={{URGENCY}}
+
+  * See on gitlab: {{URL}}/-/blob/main/CHANGELOG.md
+
+ -- MichaΓ«l Minelli <dojo@minelli.me>  {{DATE}}
\ No newline at end of file
diff --git a/Resources/Debian/pkg/DEBIAN/compat b/Resources/Debian/pkg/DEBIAN/compat
new file mode 100644
index 0000000000000000000000000000000000000000..f599e28b8ab0d8c9c57a486c89c4a5132dcbd3b2
--- /dev/null
+++ b/Resources/Debian/pkg/DEBIAN/compat
@@ -0,0 +1 @@
+10
diff --git a/Resources/Debian/pkg/DEBIAN/control b/Resources/Debian/pkg/DEBIAN/control
new file mode 100644
index 0000000000000000000000000000000000000000..8f5ce246d783bcfdd48f6d6db7bb5eda7a886eed
--- /dev/null
+++ b/Resources/Debian/pkg/DEBIAN/control
@@ -0,0 +1,47 @@
+Source: {{BIN_NAME}}
+Version: {{VERSION}}
+Standards-Version: {{VERSION}}
+Section: education
+Priority: optional
+Maintainer: MichaΓ«l Minelli <dojo@minelli.me>
+Package: {{BIN_NAME}}
+Architecture: {{ARCH}}
+Description: Dojo: a platform to practice programming
+ The Dojo platform is an online tool built to help practice programming by
+ allowing users to propose assignments and perform them as exercises.
+ .
+ The tool is very flexible and allows for proposing exercises for any language
+ and does not impose any limitation on a framework to be heavily relying
+ on Docker and Gitlab. These tools used in combination allow for automatic
+ correction of assignments in order to give immediate feedback to users
+ performing exercises. Solved exercises can then be shared among the community
+ of users such that they can inspire other users or give hints on ways to solve
+ a given exercise.
+ .
+ The two major concepts of the platform are the **assignments** and the **exercises**.
+ .
+ The principal way to interact with the Dojo platform is currently the `dojo` CLI.
+ .
+ .
+ ## The assignment
+ .
+ An assignment is written by a user that wants to propose an exercise. It is typically 
+ composed of a written description of the work to be performed, and tests that must be 
+ passed once the exercise is successfully performed (and some configuration files for 
+ the infrastructure of the tests such as docker files). At its core, an assignment is
+ nothing else than a git repository that can be forked in the form of an exercise and 
+ modified using standard git commands.
+ .
+ In the future a dependency tree of assignments can be created, as well as tagging for 
+ filtering purposes.
+ .
+ .
+ ## The exercise
+ .
+ An exercise is an instance of an assignment which the learner will modify in order to 
+ make it pass the automatic tests. It can be run locally on any user's machine using the 
+ dojo CLI. When the exercise is completed it is pushed on the dojo where the CI/CD tools 
+ of Gitlab can evaluate it automatically and notify the dojo platform of the result. The 
+ exercises can then be shared with other users in order to propose a wide variety of 
+ solutions and can be a base for discussion among users and with teachers.
+ For a more detailed description please see the CLI documentation: https://gitedu.hesge.ch/dojo_project/projects/ui/dojocli/-/wikis/home
diff --git a/Resources/Debian/pkg/DEBIAN/copyright b/Resources/Debian/pkg/DEBIAN/copyright
new file mode 100644
index 0000000000000000000000000000000000000000..e3a927e86f8a990b5f89b2657cdb2f3cde4aae9c
--- /dev/null
+++ b/Resources/Debian/pkg/DEBIAN/copyright
@@ -0,0 +1,573 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: {{BIN_NAME}}
+Upstream-Contact: MichaΓ«l Minelli <dojo@minelli.me>
+Source: https://gitedu.hesge.ch/dojo_project/projects/ui/dojocli.git
+
+Files: *
+Copyright: 
+    Development by:
+      * MichaΓ«l Minelli <dojo@minelli.me>
+      * Orestis Malaspinas <orestis.malaspinas@hesge.ch>
+License: AGPL-3
+
+License: AGPL-3
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ .
+ Version 3, 19 November 2007
+ .
+ Copyright Β© 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies of this license
+ document, but changing it is not allowed.
+ Preamble
+ .
+ The GNU Affero General Public License is a free, copyleft license for
+ software and other kinds of works, specifically designed to ensure
+ cooperation with the community in the case of network server software.
+ .
+ The licenses for most software and other practical works are designed to
+ take away your freedom to share and change the works. By contrast, our
+ General Public Licenses are intended to guarantee your freedom to share and
+ change all versions of a program--to make sure it remains free software for
+ all its users.
+ .
+ When we speak of free software, we are referring to freedom, not price. Our
+ General Public Licenses are designed to make sure that you have the freedom
+ to distribute copies of free software (and charge for them if you wish),
+ that you receive source code or can get it if you want it, that you can
+ change the software or use pieces of it in new free programs, and that you
+ know you can do these things.
+ .
+ Developers that use our General Public Licenses protect your rights with two
+ steps: (1) assert copyright on the software, and (2) offer you this License
+ which gives you legal permission to copy, distribute and/or modify the
+ software.
+ .
+ A secondary benefit of defending all users' freedom is that improvements
+ made in alternate versions of the program, if they receive widespread use,
+ become available for other developers to incorporate. Many developers of
+ free software are heartened and encouraged by the resulting cooperation.
+ However, in the case of software used on network servers, this result may
+ fail to come about. The GNU General Public License permits making a modified
+ version and letting the public access it on a server without ever releasing
+ its source code to the public.
+ .
+ The GNU Affero General Public License is designed specifically to ensure
+ that, in such cases, the modified source code becomes available to the
+ community. It requires the operator of a network server to provide the
+ source code of the modified version running there to the users of that
+ server. Therefore, public use of a modified version, on a publicly
+ accessible server, gives the public access to the source code of the
+ modified version.
+ .
+ An older license, called the Affero General Public License and published by
+ Affero, was designed to accomplish similar goals. This is a different
+ license, not a version of the Affero GPL, but Affero has released a new
+ version of the Affero GPL which permits relicensing under this license.
+ .
+ The precise terms and conditions for copying, distribution and modification
+ follow.
+ TERMS AND CONDITIONS
+ 0. Definitions.
+ .
+ "This License" refers to version 3 of the GNU Affero General Public License.
+ .
+ "Copyright" also means copyright-like laws that apply to other kinds of
+ works, such as semiconductor masks.
+ .
+ "The Program" refers to any copyrightable work licensed under this License.
+ Each licensee is addressed as "you". "Licensees" and "recipients" may be
+ individuals or organizations.
+ .
+ To "modify" a work means to copy from or adapt all or part of the work in a
+ fashion requiring copyright permission, other than the making of an exact
+ copy. The resulting work is called a "modified version" of the earlier work
+ or a work "based on" the earlier work.
+ .
+ A "covered work" means either the unmodified Program or a work based on the
+ Program.
+ .
+ To "propagate" a work means to do anything with it that, without permission,
+ would make you directly or secondarily liable for infringement under
+ applicable copyright law, except executing it on a computer or modifying a
+ private copy. Propagation includes copying, distribution (with or without
+ modification), making available to the public, and in some countries other
+ activities as well.
+ .
+ To "convey" a work means any kind of propagation that enables other parties
+ to make or receive copies. Mere interaction with a user through a computer
+ network, with no transfer of a copy, is not conveying.
+ .
+ An interactive user interface displays "Appropriate Legal Notices" to the
+ extent that it includes a convenient and prominently visible feature that
+ (1) displays an appropriate copyright notice, and (2) tells the user that
+ there is no warranty for the work (except to the extent that warranties are
+ provided), that licensees may convey the work under this License, and how to
+ view a copy of this License. If the interface presents a list of user
+ commands or options, such as a menu, a prominent item in the list meets this
+ criterion.
+ 1. Source Code.
+ .
+ The "source code" for a work means the preferred form of the work for making
+ modifications to it. "Object code" means any non-source form of a work.
+ .
+ A "Standard Interface" means an interface that either is an official
+ standard defined by a recognized standards body, or, in the case of
+ interfaces specified for a particular programming language, one that is
+ widely used among developers working in that language.
+ .
+ The "System Libraries" of an executable work include anything, other than
+ the work as a whole, that (a) is included in the normal form of packaging a
+ Major Component, but which is not part of that Major Component, and (b)
+ serves only to enable use of the work with that Major Component, or to
+ implement a Standard Interface for which an implementation is available to
+ the public in source code form. A "Major Component", in this context, means
+ a major essential component (kernel, window system, and so on) of the
+ specific operating system (if any) on which the executable work runs, or a
+ compiler used to produce the work, or an object code interpreter used to run
+ it.
+ .
+ The "Corresponding Source" for a work in object code form means all the
+ source code needed to generate, install, and (for an executable work) run
+ the object code and to modify the work, including scripts to control those
+ activities. However, it does not include the work's System Libraries, or
+ general-purpose tools or generally available free programs which are used
+ unmodified in performing those activities but which are not part of the
+ work. For example, Corresponding Source includes interface definition files
+ associated with source files for the work, and the source code for shared
+ libraries and dynamically linked subprograms that the work is specifically
+ designed to require, such as by intimate data communication or control flow
+ between those subprograms and other parts of the work.
+ .
+ The Corresponding Source need not include anything that users can regenerate
+ automatically from other parts of the Corresponding Source.
+ .
+ The Corresponding Source for a work in source code form is that same work.
+ 2. Basic Permissions.
+ .
+ All rights granted under this License are granted for the term of copyright
+ on the Program, and are irrevocable provided the stated conditions are met.
+ This License explicitly affirms your unlimited permission to run the
+ unmodified Program. The output from running a covered work is covered by
+ this License only if the output, given its content, constitutes a covered
+ work. This License acknowledges your rights of fair use or other equivalent,
+ as provided by copyright law.
+ .
+ You may make, run and propagate covered works that you do not convey,
+ without conditions so long as your license otherwise remains in force. You
+ may convey covered works to others for the sole purpose of having them make
+ modifications exclusively for you, or provide you with facilities for
+ running those works, provided that you comply with the terms of this License
+ in conveying all material for which you do not control copyright. Those thus
+ making or running the covered works for you must do so exclusively on your
+ behalf, under your direction and control, on terms that prohibit them from
+ making any copies of your copyrighted material outside their relationship
+ with you.
+ .
+ Conveying under any other circumstances is permitted solely under the
+ conditions stated below. Sublicensing is not allowed; section 10 makes it
+ unnecessary.
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+ .
+ No covered work shall be deemed part of an effective technological measure
+ under any applicable law fulfilling obligations under article 11 of the WIPO
+ copyright treaty adopted on 20 December 1996, or similar laws prohibiting or
+ restricting circumvention of such measures.
+ .
+ When you convey a covered work, you waive any legal power to forbid
+ circumvention of technological measures to the extent such circumvention is
+ effected by exercising rights under this License with respect to the covered
+ work, and you disclaim any intention to limit operation or modification of
+ the work as a means of enforcing, against the work's users, your or third
+ parties' legal rights to forbid circumvention of technological measures.
+ 4. Conveying Verbatim Copies.
+ .
+ You may convey verbatim copies of the Program's source code as you receive
+ it, in any medium, provided that you conspicuously and appropriately publish
+ on each copy an appropriate copyright notice; keep intact all notices
+ stating that this License and any non-permissive terms added in accord with
+ section 7 apply to the code; keep intact all notices of the absence of any
+ warranty; and give all recipients a copy of this License along with the
+ Program.
+ .
+ You may charge any price or no price for each copy that you convey, and you
+ may offer support or warranty protection for a fee.
+ 5. Conveying Modified Source Versions.
+ .
+ You may convey a work based on the Program, or the modifications to produce
+ it from the Program, in the form of source code under the terms of section
+ 4, provided that you also meet all of these conditions:
+ .
+     a) The work must carry prominent notices stating that you modified it,
+ and giving a relevant date.
+     b) The work must carry prominent notices stating that it is released
+ under this License and any conditions added under section 7. This
+ requirement modifies the requirement in section 4 to "keep intact all
+ notices".
+     c) You must license the entire work, as a whole, under this License to
+ anyone who comes into possession of a copy. This License will therefore
+ apply, along with any applicable section 7 additional terms, to the whole of
+ the work, and all its parts, regardless of how they are packaged. This
+ License gives no permission to license the work in any other way, but it
+ does not invalidate such permission if you have separately received it.
+     d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your work need not
+ make them do so.
+ .
+ A compilation of a covered work with other separate and independent works,
+ which are not by their nature extensions of the covered work, and which are
+ not combined with it such as to form a larger program, in or on a volume of
+ a storage or distribution medium, is called an "aggregate" if the
+ compilation and its resulting copyright are not used to limit the access or
+ legal rights of the compilation's users beyond what the individual works
+ permit. Inclusion of a covered work in an aggregate does not cause this
+ License to apply to the other parts of the aggregate.
+ 6. Conveying Non-Source Forms.
+ .
+ You may convey a covered work in object code form under the terms of
+ sections 4 and 5, provided that you also convey the machine-readable
+ Corresponding Source under the terms of this License, in one of these ways:
+ .
+     a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the Corresponding
+ Source fixed on a durable physical medium customarily used for software
+ interchange.
+     b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a written offer,
+ valid for at least three years and valid for as long as you offer spare
+ parts or customer support for that product model, to give anyone who
+ possesses the object code either (1) a copy of the Corresponding Source for
+ all the software in the product that is covered by this License, on a
+ durable physical medium customarily used for software interchange, for a
+ price no more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the Corresponding Source from a
+ network server at no charge.
+     c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This alternative is
+ allowed only occasionally and noncommercially, and only if you received the
+ object code with such an offer, in accord with subsection 6b.
+     d) Convey the object code by offering access from a designated place
+ (gratis or for a charge), and offer equivalent access to the Corresponding
+ Source in the same way through the same place at no further charge. You need
+ not require recipients to copy the Corresponding Source along with the
+ object code. If the place to copy the object code is a network server, the
+ Corresponding Source may be on a different server (operated by you or a
+ third party) that supports equivalent copying facilities, provided you
+ maintain clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the Corresponding
+ Source, you remain obligated to ensure that it is available for as long as
+ needed to satisfy these requirements.
+     e) Convey the object code using peer-to-peer transmission, provided you
+ inform other peers where the object code and Corresponding Source of the
+ work are being offered to the general public at no charge under subsection
+ 6d.
+ .
+ A separable portion of the object code, whose source code is excluded from
+ the Corresponding Source as a System Library, need not be included in
+ conveying the object code work.
+ .
+ A "User Product" is either (1) a "consumer product", which means any
+ tangible personal property which is normally used for personal, family, or
+ household purposes, or (2) anything designed or sold for incorporation into
+ a dwelling. In determining whether a product is a consumer product, doubtful
+ cases shall be resolved in favor of coverage. For a particular product
+ received by a particular user, "normally used" refers to a typical or common
+ use of that class of product, regardless of the status of the particular
+ user or of the way in which the particular user actually uses, or expects or
+ is expected to use, the product. A product is a consumer product regardless
+ of whether the product has substantial commercial, industrial or
+ non-consumer uses, unless such uses represent the only significant mode of
+ use of the product.
+ .
+ "Installation Information" for a User Product means any methods, procedures,
+ authorization keys, or other information required to install and execute
+ modified versions of a covered work in that User Product from a modified
+ version of its Corresponding Source. The information must suffice to ensure
+ that the continued functioning of the modified object code is in no case
+ prevented or interfered with solely because modification has been made.
+ .
+ If you convey an object code work under this section in, or with, or
+ specifically for use in, a User Product, and the conveying occurs as part of
+ a transaction in which the right of possession and use of the User Product
+ is transferred to the recipient in perpetuity or for a fixed term
+ (regardless of how the transaction is characterized), the Corresponding
+ Source conveyed under this section must be accompanied by the Installation
+ Information. But this requirement does not apply if neither you nor any
+ third party retains the ability to install modified object code on the User
+ Product (for example, the work has been installed in ROM).
+ .
+ The requirement to provide Installation Information does not include a
+ requirement to continue to provide support service, warranty, or updates for
+ a work that has been modified or installed by the recipient, or for the User
+ Product in which it has been modified or installed. Access to a network may
+ be denied when the modification itself materially and adversely affects the
+ operation of the network or violates the rules and protocols for
+ communication across the network.
+ .
+ Corresponding Source conveyed, and Installation Information provided, in
+ accord with this section must be in a format that is publicly documented
+ (and with an implementation available to the public in source code form),
+ and must require no special password or key for unpacking, reading or
+ copying.
+ 7. Additional Terms.
+ .
+ "Additional permissions" are terms that supplement the terms of this License
+ by making exceptions from one or more of its conditions. Additional
+ permissions that are applicable to the entire Program shall be treated as
+ though they were included in this License, to the extent that they are valid
+ under applicable law. If additional permissions apply only to part of the
+ Program, that part may be used separately under those permissions, but the
+ entire Program remains governed by this License without regard to the
+ additional permissions.
+ .
+ When you convey a copy of a covered work, you may at your option remove any
+ additional permissions from that copy, or from any part of it. (Additional
+ permissions may be written to require their own removal in certain cases
+ when you modify the work.) You may place additional permissions on material,
+ added by you to a covered work, for which you have or can give appropriate
+ copyright permission.
+ .
+ Notwithstanding any other provision of this License, for material you add to
+ a covered work, you may (if authorized by the copyright holders of that
+ material) supplement the terms of this License with terms:
+ .
+     a) Disclaiming warranty or limiting liability differently from the terms
+ of sections 15 and 16 of this License; or
+     b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal Notices
+ displayed by works containing it; or
+     c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in reasonable
+ ways as different from the original version; or
+     d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+     e) Declining to grant rights under trademark law for use of some trade
+ names, trademarks, or service marks; or
+     f) Requiring indemnification of licensors and authors of that material
+ by anyone who conveys the material (or modified versions of it) with
+ contractual assumptions of liability to the recipient, for any liability
+ that these contractual assumptions directly impose on those licensors and
+ authors.
+ .
+ All other non-permissive additional terms are considered "further
+ restrictions" within the meaning of section 10. If the Program as you
+ received it, or any part of it, contains a notice stating that it is
+ governed by this License along with a term that is a further restriction,
+ you may remove that term. If a license document contains a further
+ restriction but permits relicensing or conveying under this License, you may
+ add to a covered work material governed by the terms of that license
+ document, provided that the further restriction does not survive such
+ relicensing or conveying.
+ .
+ If you add terms to a covered work in accord with this section, you must
+ place, in the relevant source files, a statement of the additional terms
+ that apply to those files, or a notice indicating where to find the
+ applicable terms.
+ .
+ Additional terms, permissive or non-permissive, may be stated in the form of
+ a separately written license, or stated as exceptions; the above
+ requirements apply either way.
+ 8. Termination.
+ .
+ You may not propagate or modify a covered work except as expressly provided
+ under this License. Any attempt otherwise to propagate or modify it is void,
+ and will automatically terminate your rights under this License (including
+ any patent licenses granted under the third paragraph of section 11).
+ .
+ However, if you cease all violation of this License, then your license from
+ a particular copyright holder is reinstated (a) provisionally, unless and
+ until the copyright holder explicitly and finally terminates your license,
+ and (b) permanently, if the copyright holder fails to notify you of the
+ violation by some reasonable means prior to 60 days after the cessation.
+ .
+ Moreover, your license from a particular copyright holder is reinstated
+ permanently if the copyright holder notifies you of the violation by some
+ reasonable means, this is the first time you have received notice of
+ violation of this License (for any work) from that copyright holder, and you
+ cure the violation prior to 30 days after your receipt of the notice.
+ .
+ Termination of your rights under this section does not terminate the
+ licenses of parties who have received copies or rights from you under this
+ License. If your rights have been terminated and not permanently reinstated,
+ you do not qualify to receive new licenses for the same material under
+ section 10.
+ 9. Acceptance Not Required for Having Copies.
+ .
+ You are not required to accept this License in order to receive or run a
+ copy of the Program. Ancillary propagation of a covered work occurring
+ solely as a consequence of using peer-to-peer transmission to receive a copy
+ likewise does not require acceptance. However, nothing other than this
+ License grants you permission to propagate or modify any covered work. These
+ actions infringe copyright if you do not accept this License. Therefore, by
+ modifying or propagating a covered work, you indicate your acceptance of
+ this License to do so.
+ 10. Automatic Licensing of Downstream Recipients.
+ .
+ Each time you convey a covered work, the recipient automatically receives a
+ license from the original licensors, to run, modify and propagate that work,
+ subject to this License. You are not responsible for enforcing compliance by
+ third parties with this License.
+ .
+ An "entity transaction" is a transaction transferring control of an
+ organization, or substantially all assets of one, or subdividing an
+ organization, or merging organizations. If propagation of a covered work
+ results from an entity transaction, each party to that transaction who
+ receives a copy of the work also receives whatever licenses to the work the
+ party's predecessor in interest had or could give under the previous
+ paragraph, plus a right to possession of the Corresponding Source of the
+ work from the predecessor in interest, if the predecessor has it or can get
+ it with reasonable efforts.
+ .
+ You may not impose any further restrictions on the exercise of the rights
+ granted or affirmed under this License. For example, you may not impose a
+ license fee, royalty, or other charge for exercise of rights granted under
+ this License, and you may not initiate litigation (including a cross-claim
+ or counterclaim in a lawsuit) alleging that any patent claim is infringed by
+ making, using, selling, offering for sale, or importing the Program or any
+ portion of it.
+ 11. Patents.
+ .
+ A "contributor" is a copyright holder who authorizes use under this License
+ of the Program or a work on which the Program is based. The work thus
+ licensed is called the contributor's "contributor version".
+ .
+ A contributor's "essential patent claims" are all patent claims owned or
+ controlled by the contributor, whether already acquired or hereafter
+ acquired, that would be infringed by some manner, permitted by this License,
+ of making, using, or selling its contributor version, but do not include
+ claims that would be infringed only as a consequence of further modification
+ of the contributor version. For purposes of this definition, "control"
+ includes the right to grant patent sublicenses in a manner consistent with
+ the requirements of this License.
+ .
+ Each contributor grants you a non-exclusive, worldwide, royalty-free patent
+ license under the contributor's essential patent claims, to make, use, sell,
+ offer for sale, import and otherwise run, modify and propagate the contents
+ of its contributor version.
+ .
+ In the following three paragraphs, a "patent license" is any express
+ agreement or commitment, however denominated, not to enforce a patent (such
+ as an express permission to practice a patent or covenant not to sue for
+ patent infringement). To "grant" such a patent license to a party means to
+ make such an agreement or commitment not to enforce a patent against the
+ party.
+ .
+ If you convey a covered work, knowingly relying on a patent license, and the
+ Corresponding Source of the work is not available for anyone to copy, free
+ of charge and under the terms of this License, through a publicly available
+ network server or other readily accessible means, then you must either (1)
+ cause the Corresponding Source to be so available, or (2) arrange to deprive
+ yourself of the benefit of the patent license for this particular work, or
+ (3) arrange, in a manner consistent with the requirements of this License,
+ to extend the patent license to downstream recipients. "Knowingly relying"
+ means you have actual knowledge that, but for the patent license, your
+ conveying the covered work in a country, or your recipient's use of the
+ covered work in a country, would infringe one or more identifiable patents
+ in that country that you have reason to believe are valid.
+ .
+ If, pursuant to or in connection with a single transaction or arrangement,
+ you convey, or propagate by procuring conveyance of, a covered work, and
+ grant a patent license to some of the parties receiving the covered work
+ authorizing them to use, propagate, modify or convey a specific copy of the
+ covered work, then the patent license you grant is automatically extended to
+ all recipients of the covered work and works based on it.
+ .
+ A patent license is "discriminatory" if it does not include within the scope
+ of its coverage, prohibits the exercise of, or is conditioned on the
+ non-exercise of one or more of the rights that are specifically granted
+ under this License. You may not convey a covered work if you are a party to
+ an arrangement with a third party that is in the business of distributing
+ software, under which you make payment to the third party based on the
+ extent of your activity of conveying the work, and under which the third
+ party grants, to any of the parties who would receive the covered work from
+ you, a discriminatory patent license (a) in connection with copies of the
+ covered work conveyed by you (or copies made from those copies), or (b)
+ primarily for and in connection with specific products or compilations that
+ contain the covered work, unless you entered into that arrangement, or that
+ patent license was granted, prior to 28 March 2007.
+ .
+ Nothing in this License shall be construed as excluding or limiting any
+ implied license or other defenses to infringement that may otherwise be
+ available to you under applicable patent law.
+ 12. No Surrender of Others' Freedom.
+ .
+ If conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot convey a
+ covered work so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you may
+ not convey it at all. For example, if you agree to terms that obligate you
+ to collect a royalty for further conveying from those to whom you convey the
+ Program, the only way you could satisfy both those terms and this License
+ would be to refrain entirely from conveying the Program.
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+ .
+ Notwithstanding any other provision of this License, if you modify the
+ Program, your modified version must prominently offer all users interacting
+ with it remotely through a computer network (if your version supports such
+ interaction) an opportunity to receive the Corresponding Source of your
+ version by providing access to the Corresponding Source from a network
+ server at no charge, through some standard or customary means of
+ facilitating copying of software. This Corresponding Source shall include
+ the Corresponding Source for any work covered by version 3 of the GNU
+ General Public License that is incorporated pursuant to the following
+ paragraph.
+ .
+ Notwithstanding any other provision of this License, you have permission to
+ link or combine any covered work with a work licensed under version 3 of the
+ GNU General Public License into a single combined work, and to convey the
+ resulting work. The terms of this License will continue to apply to the part
+ which is the covered work, but the work with which it is combined will
+ remain governed by version 3 of the GNU General Public License.
+ 14. Revised Versions of this License.
+ .
+ The Free Software Foundation may publish revised and/or new versions of the
+ GNU Affero General Public License from time to time. Such new versions will
+ be similar in spirit to the present version, but may differ in detail to
+ address new problems or concerns.
+ .
+ Each version is given a distinguishing version number. If the Program
+ specifies that a certain numbered version of the GNU Affero General Public
+ License "or any later version" applies to it, you have the option of
+ following the terms and conditions either of that numbered version or of any
+ later version published by the Free Software Foundation. If the Program does
+ not specify a version number of the GNU Affero General Public License, you
+ may choose any version ever published by the Free Software Foundation.
+ .
+ If the Program specifies that a proxy can decide which future versions of
+ the GNU Affero General Public License can be used, that proxy's public
+ statement of acceptance of a version permanently authorizes you to choose
+ that version for the Program.
+ .
+ Later license versions may give you additional or different permissions.
+ However, no additional obligations are imposed on any author or copyright
+ holder as a result of your choosing to follow a later version.
+ 15. Disclaimer of Warranty.
+ .
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
+ LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+ OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
+ EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.
+ SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+ SERVICING, REPAIR OR CORRECTION.
+ 16. Limitation of Liability.
+ .
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
+ ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE
+ PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
+ OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
+ OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGES.
+ 17. Interpretation of Sections 15 and 16.
+ .
+ If the disclaimer of warranty and limitation of liability provided above
+ cannot be given local legal effect according to their terms, reviewing
+ courts shall apply local law that most closely approximates an absolute
+ waiver of all civil liability in connection with the Program, unless a
+ warranty or assumption of liability accompanies a copy of the Program in
+ return for a fee.
\ No newline at end of file
diff --git a/Resources/Debian/pkg/DEBIAN/rules b/Resources/Debian/pkg/DEBIAN/rules
new file mode 100755
index 0000000000000000000000000000000000000000..7903e6f86e772cbcd0b480b198a49be5443852f4
--- /dev/null
+++ b/Resources/Debian/pkg/DEBIAN/rules
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+#DH_VERBOSE = 1
+ 
+# see FEATURE AREAS in dpkg-buildflags(1)
+#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# see ENVIRONMENT in dpkg-buildflags(1)
+# package maintainers to append CFLAGS
+#export DEB_CFLAGS_MAINT_APPEND  = -Wall -pedantic
+# package maintainers to append LDFLAGS
+#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
+
+
+%:
+    dh $@
\ No newline at end of file
diff --git a/Resources/Debian/pkg/usr/local/bin/.gitkeep b/Resources/Debian/pkg/usr/local/bin/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Resources/macApp/Signing/entitlements.plist b/Resources/macOS/Signing/entitlements.plist
similarity index 100%
rename from Resources/macApp/Signing/entitlements.plist
rename to Resources/macOS/Signing/entitlements.plist
diff --git a/Wiki/0-Dojo-presentation.md b/Wiki/0-Dojo-presentation.md
new file mode 100644
index 0000000000000000000000000000000000000000..6b57243843561093f1e74debe2fcfc426fb7ba16
--- /dev/null
+++ b/Wiki/0-Dojo-presentation.md
@@ -0,0 +1,37 @@
+# Dojo: a platform to practice programming
+
+The dojo platform is an online tool built to help practice programming by
+allowing users to propose assignments and perform them as exercises.
+
+The tool is very flexible and allows for proposing exercises for any language
+and does not impose any limitation on a framework to be heavily relying
+on Docker and Gitlab. These tools used in combination allow for automatic
+correction of assignments in order to give immediate feedback to users
+performing exercises. Solved exercises can then be shared among the community
+of users such that they can inspire other users or give hints on ways to solve
+a given exercise.
+
+The two major concepts of the platform are the **assignments** and the **exercises**.
+
+The principal way to interact with the Dojo platform is currently the `dojo` CLI.
+
+## The assignment
+
+An assignment is written by a user that wants to propose an exercise. It is typically composed of a written description of the work to be performed,
+and tests that must be passed once the exercise is successfully performed (and some configuration files for the infrastructure of the tests
+such as docker files). At its core, an assignment is
+nothing else than a git repository that can be forked in the form of an exercise and modified using standard git commands.
+For a more detailed description please see the [CLI documentation](home).
+An assignment can be proposed by any user.
+
+In the future a dependency tree of assignments can be created, as well as tagging for filtering purposes.
+
+## The exercise
+
+An exercise is an instance of an assignment which the learner will modify in order to make it pass the automatic tests.
+It can be run locally on any user's machine using the dojo CLI. When the exercise is completed
+it is pushed on the dojo where the CI/CD tools of Gitlab can evaluate it automatically and
+notify the dojo platform of the result. The exercises can then be shared with other users
+in order to propose a wide variety of solutions and can be a base for discussion among users
+and with teachers.
+For a more detailed description please see the [CLI documentation](home).
\ No newline at end of file
diff --git a/Wiki/Tutorials/0-Exercise-perform.md b/Wiki/Tutorials/0-Exercise-perform.md
new file mode 100644
index 0000000000000000000000000000000000000000..e2ca1b442ba52137db823f1bd62b38b6a31ab1c0
--- /dev/null
+++ b/Wiki/Tutorials/0-Exercise-perform.md
@@ -0,0 +1,154 @@
+# How to perform an exercise
+
+In this tutorial we quickly explain the workflow for performing an exercise by a student (or a professor).
+The exercise is based on the `c_hello_world` assignment created in [assignment creation](1-Assignment-creation) tutorial.
+
+## Exercise "creation"
+
+To perform an exercise the student must first create the exercise. Under the hood, this operation consist in making 
+a fork of a published assignment in the student's namespace.
+
+This is performed by the following `dojo` command:
+```bash
+$ dojo exercise create --assignment c_hello_world
+```
+```console
+Please wait while we verify and retrieve data...
+β„Ή Checking Dojo session: 
+    βœ” The session is valid
+        βœ” Student permissions
+β„Ή Checking Gitlab token: 
+    βœ” Read access
+    βœ” Write access
+β„Ή Checking assignment:
+    βœ” Assignment "c_hello_world" exists
+    βœ” Assignment "c_hello_world" is published
+Please wait while we are creating the exercise...
+βœ” Exercise successfully created
+    β„Ή Id: 8d3f53a0-0d32-4455-a251-e1a1c5a97c6a
+    β„Ή Name: DojoEx - c_hello_world - orestis.malaspin - 1
+    β„Ή Web URL: https://gitedu.hesge.ch/dojo/exercise/dojo-ex_c_hello_world_8d3f53a0-0d32-4455-a251-e1a1c5a97c6a
+    β„Ή HTTP Repo: https://gitedu.hesge.ch/dojo/exercise/dojo-ex_c_hello_world_8d3f53a0-0d32-4455-a251-e1a1c5a97c6a.git
+    β„Ή SSH Repo: ssh://git@ssh.hesge.ch:10572/dojo/exercise/dojo-ex_c_hello_world_8d3f53a0-0d32-4455-a251-e1a1c5a97c6a.git
+```
+
+## To perform the exercise
+
+The exercise is nothing else than a git repository so the workflow is pretty straightforward.
+
+1. Clone the repository (see the repo link above)
+```bash
+$ git clone ssh://git@ssh.hesge.ch:10572/dojo/exercise/dojo-ex_c_hello_world_8d3f53a0-0d32-4455-a251-e1a1c5a97c6a.git
+```
+```console
+Cloning into 'dojo-ex_c_hello_world_8d3f53a0-0d32-4455-a251-e1a1c5a97c6a'...
+remote: Enumerating objects: 33, done.
+remote: Counting objects: 100% (33/33), done.
+remote: Compressing objects: 100% (26/26), done.
+remote: Total 33 (delta 6), reused 16 (delta 3), pack-reused 0
+Receiving objects: 100% (33/33), 7.32 KiB | 7.32 MiB/s, done.
+Resolving deltas: 100% (6/6), done.
+```
+2. Read the `README.md` file to understand what is expected by the teacher.
+3. Modify/create the appropriate code.
+4. (Optional but recommended) Execute the pipeline locally
+```bash
+$ dojo exercise run
+```
+```console
+Please wait while we are checking and creating dependencies...
+    β„Ή Checking exercise content:
+        βœ” The exercise folder contains all the needed files
+        βœ” The dojo_assignment.json file is valid
+    βœ” The Docker deamon is running
+Please wait while we are running the exercise...
+    βœ” Docker Compose file run successfully
+    βœ” Linked services logs acquired
+    βœ” Containers stopped and removed
+Please wait while we are checking the results...
+    βœ” Results file found
+    βœ” Results file is valid
+    βœ” Results folder size is in bounds
+
+   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Results ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+   ┃                                                                                                    ┃
+   ┃   Global result : ❌ Failure                                                                       ┃
+   ┃                                                                                                    ┃
+   ┃   Execution exit code : 0                                                                          ┃
+   ┃                                                                                                    ┃
+   ┃   Execution results folder : /home/student/DojoExecutions/dojo_execLogs_2023-08-30T18_58_05_764Z   ┃
+   ┃                                                                                                    ┃
+   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+```
+Currently the exercise is a failure which is sad but expected since there was no modification in any file.
+One can see that we have access to a `results` folder in `/home/student/DojoExecutions/dojo_execLogs_2023-08-30T18_58_05_764Z`.
+This directory contains the output of the pipeline execution
+```console
+/home/student/DojoExecutions/dojo_execLogs_2023-08-30T18_58_05_764Z
+β”œβ”€β”€ Dojo
+β”‚   β”œβ”€β”€ dockerComposeLogs.txt
+β”‚   └── results.json
+└── Exercise
+    └── diff_output.txt
+
+2 directories, 3 files
+```
+In particular one can find the output the teacher wanted us (students) to see in the `Exercise` folder.
+It contains any output file that can be used for debugging for example. In this case it contains
+```console
+< ./hello_world
+< (null)
+\ No newline at end of file
+---
+> Hello world!
+\ No newline at end of file
+```
+One can see that there is an `Hello world!` expected and that no `Hello world!` was provided by our program.
+One can also see the complete
+logs of the `docker compose` command in `Dojo/dockerComposeLogs.txt` which may (or may not)
+provide additional informations.
+
+In order to complete this assignment we have to modify the `src/function.c` file such that it becomes
+```c
+#include "function.h"
+
+char *hello_world()
+{
+    return "Hello world!";
+}
+```
+Rerunning the pipeline now yields
+```bash
+$ dojo exercise run
+```
+```console
+Please wait while we are checking and creating dependencies...
+    β„Ή Checking exercise content:
+        βœ” The exercise folder contains all the needed files
+        βœ” The dojo_assignment.json file is valid
+    βœ” The Docker deamon is running
+Please wait while we are running the exercise...
+    βœ” Docker Compose file run successfully
+    βœ” Linked services logs acquired
+    βœ” Containers stopped and removed
+Please wait while we are checking the results...
+    βœ” Results file found
+    βœ” Results file is valid
+    βœ” Results folder size is in bounds
+
+   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Results ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+   ┃                                                                                                    ┃
+   ┃   Global result : βœ… Success                                                                       ┃
+   ┃                                                                                                    ┃
+   ┃   Execution exit code : 0                                                                          ┃
+   ┃                                                                                                    ┃
+   ┃   Execution results folder : /home/student/DojoExecutions/dojo_execLogs_2023-08-30T19_20_25_104Z   ┃
+   ┃                                                                                                    ┃
+   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+```
+5. Now that we are happy with the state of our exercise, we can commit and push our modifications and
+the exercise will be run through the Gitlab CI pipeline and one can see the "official" result
+of our exercise.
+![The Gitlab CI pipeline succeeded!](pipeline.png)
+It is not necessary to have a successful pipeline to commit and push the code. We can do it at any time
+which is particularly useful when doing long assignments that take many iterations to finish.
diff --git a/Wiki/Tutorials/1-Assignment-creation.md b/Wiki/Tutorials/1-Assignment-creation.md
new file mode 100644
index 0000000000000000000000000000000000000000..16441292665f46c699b6d6fb419dd9129f430504
--- /dev/null
+++ b/Wiki/Tutorials/1-Assignment-creation.md
@@ -0,0 +1,414 @@
+# How to create an assignment
+
+We will describe how to create a very simple assignment with dojo.
+
+Here we will build a `Hello world!` in the C programming language. We will describe how one must
+modify the default template to have an exercise.
+
+The exercise will be to fill a function to return the `Hello world!` string.
+The output of the function will be printed on the standard output.
+The structure will be provided to the students as well as a very simple `Makefile`
+to compile and run the code.
+
+The success or failure of this assignment will be tested by comparing the output
+of our program with an the expected output (the famous `Hello world!`).
+
+To build this exercise we need to perform several steps that will be described below in great details.
+
+## Empty assignment creation
+
+First create a new assignment with the command
+```bash
+$ dojo assignment create --name c_hello_world
+```
+```console
+Please wait while we verify and retrieve data...
+β„Ή Checking Dojo session: 
+    βœ” The session is valid
+        βœ” Teaching staff permissions
+β„Ή Checking Gitlab token: 
+    βœ” Read access
+    βœ” Write access
+βœ” Assignment name "c_hello_world" is available
+Please wait while we are creating the assignment...
+βœ” Assignment successfully created
+    β„Ή Name: c_hello_world
+    β„Ή Web URL: https://gitedu.hesge.ch/dojo/assignment/c_hello_world
+    β„Ή HTTP Repo: https://gitedu.hesge.ch/dojo/assignment/c_hello_world.git
+    β„Ή SSH Repo: ssh://git@ssh.hesge.ch:10572/dojo/assignment/c_hello_world.git
+```
+
+## Clone the assignment locally
+
+The assignment is nothing more than a git repository. We just clone it and start
+modifying it
+```bash
+$ git clone ssh://git@ssh.hesge.ch:10572/dojo/assignment/c_hello_world.git
+```
+```console
+Cloning into 'c_hello_world'...
+remote: Enumerating objects: 18, done.
+remote: Counting objects: 100% (18/18), done.
+remote: Compressing objects: 100% (12/12), done.
+remote: Total 18 (delta 3), reused 18 (delta 3), pack-reused 0
+Receiving objects: 100% (18/18), 4.37 KiB | 4.37 MiB/s, done.
+Resolving deltas: 100% (3/3), done.
+```
+The `c_hello_world` assignment has now the following structure
+```bash
+$ tree c_hello_world/
+```
+```console
+c_hello_world/
+β”œβ”€β”€ docker-compose.yml
+β”œβ”€β”€ Dockerfile
+β”œβ”€β”€ dojo.assignment
+└── README.md
+```
+
+## Build the development environment
+
+In order to execute a C program we need a working compiler and `make`. In order to
+produce a special result file to be parsed by the `dojo` tool to produce nicely formatted output
+we will use `jq`, a command-line json creation/edition/reding tool. Our `Dockerfile`
+contains
+```dockerfile
+FROM ubuntu:latest
+RUN apt update && apt install gcc make jq -y
+COPY . /
+ENTRYPOINT ["./run.sh"]
+```
+We see that we start by installing the required packages on top of the latest Ubuntu image.
+We then proceed to copy the complete assignment into the docker container, finall we run
+a yet to be created `run.sh` script.
+
+We can test our `Dockerfile` by running the command
+```bash
+$ docker compose run --build hello_world
+```
+```console
+[+] Building 20.5s (8/8) FINISHED                                 
+ => [hello_world internal] load build definition from Dockerfile
+ => => transferring dockerfile: 134B
+ => [hello_world internal] load .dockerignore
+ => => transferring context: 2B
+ => [hello_world internal] load metadata for docker.io/library/ubuntu:latest
+ => CACHED [hello_world 1/3] FROM docker.io/library/ubuntu:latest@sha256:ec050c32e4a6085b423d36ecd025c0d3ff00c38ab93a3d71a460ff1c44fa6d77
+ => [hello_world internal] load build context
+ => => transferring context: 39.87kB
+ => [hello_world 2/3] RUN apt update && apt install gcc make jq -y
+ => [hello_world 3/3] COPY . /
+ => [hello_world] exporting to image
+ => => exporting layers
+ => => writing image sha256:4b561113c7123da08206a2cf2642cb4f331670fe44350646437eaa78e44aff3a
+ => => naming to docker.io/library/c_hello_world-hello_world
+ERRO[0021] error waiting for container:                                   
+Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "./run.sh": stat ./run.sh: no such file or directory: unknown
+```
+We see an error at the end of the command which is perfectly normal. We did not create the `run.sh` file et (let's leave that for later).
+
+We then need to focus on the `docker-compose.yml` file which will take care of all the hard work
+needed if complex workflows are required. Here it is as simple as possible and should contain
+```yml
+services:
+    hello_world:
+        container_name: hello_world
+        build:
+            context: ./
+            dockerfile: Dockerfile
+        volumes:
+            - hello_world_volume:/result # <hello_world_volume> must be the same as below but
+                                         # the name may be arbitrary. This volume must be 
+                                         # present in the dojo_assignment.json file under the field
+                                         # "result": {
+                                         #   "volume": "hello_world_volume", 
+                                         #    ...
+                                         # }
+volumes:
+    hello_world_volume:
+```
+In this file, we see the definition of a `hello_world_volume` this is an arbitrary name and can be changed but it
+must be coherent in this file and in the `dojo_assignment.json` file (more on this later configuration file in [The dojo configuration file](#the-dojo-configuration-file)).
+This volume is responsible of mounting `/result/` directory which will contain all
+the output generated by our assignment (again the name can be changed). In particular
+in this director e will be required to create a `dojo_assignment.json` file
+that contains at least if the assignment was successfully performed (more on that at the end of the [Creating the assignment files](#creating-the-assignment-files) section).
+
+## The dojo configuration file
+
+The `dojo_assignment.json` file contains the general configuration of the assignment. 
+The important configuration parameters are:
+- the *immutable files* which are files that will be overwritten when the compilation pipeline is run (even if the student
+modifies these files the modifications will not be taken into account),
+- the *results* which is the volume corresponding to the `docker-compose.yml` file.
+
+In its default form `dojo_assignment.json` file contains
+```json
+{
+  "dojoAssignmentVersion": 1,
+  "version": 1,
+  "immutable": [
+    {
+      "description": "Dockerfile of the unique container",
+      "path": "Dockerfile",
+      "isDirectory": false
+    }
+  ],
+  "result": {
+    "container": "hello_world",
+    "volume": "hello_world_volume"
+  }
+}
+```
+Here we see only one immutable file which is the `Dockerfile` (the `isDirectory` field is `false` but it is possible to make
+complete directories immutable) and we see that:
+* the value of the `container` field (`hello_world`) corresponds to
+the value of the `container_name` field in the `docker-compose.yml` file,
+* the value of the `volume` field (`hello_world_volume`) corresponds to the `volumes` field in the `docker-compose.yml` file.
+
+This file will be completed in [The immutable files](#the-immutable-files) sectino with the files of our assignment that will be
+created in the [next section](#creating-the-assignment-files).
+
+## Creating the assignment files
+
+For this assignment we will create the following files with the following content:
+
+- `src/Makefile`
+```makefile
+CC:=gcc
+CFLAGS:=-Wall -Wextra -Wpedantic -fsanitize=address  -Werror -g
+LDFLAGS:=-fsanitize=address
+
+hello_world: hello_world.o function.o
+	gcc -o $@ $^ $(LDFLAGS)
+
+hello_world.o: function.h
+
+function.o: function.h
+
+run: hello_world
+	./hello_world
+
+clean: 
+	rm -f *.o hello_world
+```
+- `src/hello_world.c`
+```c
+#include <stdio.h>
+#include <stdlib.h>
+#include "function.h"
+
+int main()
+{
+    printf("%s", hello_world());
+    return EXIT_SUCCESS;
+}
+```
+- `src/function.h`
+```c
+#ifndef _FUNCTION_H_
+#define _FUNCTION_H_
+
+char *hello_world();
+
+#endif
+```
+- `src/function.c`
+```c
+#include "function.h"
+
+char *hello_world()
+{
+    // TODO: Replace 0 here to return "Hello world!"
+    return 0;
+}
+```
+- `src/expected_output.txt`
+```
+Hello world!
+```
+
+These files will be used to create an executable that will be run by the custom execution script, `run.sh`, see the `Dockerfile` in
+the [Build the environment](#build-the-development-environment) section.
+
+All these files have arbitrary names and it's completely up to the teacher to make a coherent exercise.
+
+The only missing file is `run.sh` (do not forget to make it executable, `chmod +x run.sh`) that contains the following code
+```bash
+#!/bin/bash
+
+echo "Starting tests."
+
+GLOBAL_SUCCESS=false
+
+make -C src clean -s
+make -C src -s
+if [ $? -eq 0 ]; then
+    make run -C src > src/output.txt -s
+    if [ $? -eq 0 ]; then
+        diff --color src/output.txt src/expected_output.txt > result/diff_output.txt
+        if [ $? -ne 0 ]; then
+            echo "Output is wrong:";
+            cat result/diff_output.txt
+        else
+            echo "All tests were a complete success"
+            GLOBAL_SUCCESS=true
+        fi
+        
+    else
+        echo "Execution failed";
+    fi
+else
+    echo "Compilation failed."
+fi
+
+jq --null-input --arg success $GLOBAL_SUCCESS \
+    '{"success": $success | test("true")}' > /result/results.json
+```
+Here one can see the creation of two different files that are located in the `result` directory:
+- `result/results.json`
+- `result/diff_output.txt`
+The `results.json` is mandatory to be created and must at least contain the
+`success` field must be `true` or `false` and determines whether the
+assignment is a success or a failure. The other files present in the `result` folder
+can be retrieved by the students.
+
+To test if everything works according to plan, one can again use the command
+```bash
+$ docker compose run --build hello_world
+```
+```console
+[+] Building 1.8s (8/8) FINISHED                                                                                    
+ => [hello_world internal] load build definition from Dockerfile
+ => => transferring dockerfile: 134B
+ => [hello_world internal] load .dockerignore
+ => => transferring context: 2B
+ => [hello_world internal] load metadata for docker.io/library/ubuntu:latest
+ => [hello_world 1/3] FROM docker.io/library/ubuntu:latest@sha256:ec050c32e4a6085b423d36ecd025c0d3ff00c38ab93
+ => [hello_world internal] load build context
+ => => transferring context: 3.23kB
+ => CACHED [hello_world 2/3] RUN apt update && apt install gcc make jq -y
+ => [hello_world 3/3] COPY . /
+ => [hello_world] exporting to image
+ => => exporting layers
+ => => writing image sha256:5499aa3aa0b2f2021584dbf46b4b05ab83dc0a5ad4d6c81a3466c56673c3f562
+ => => naming to docker.io/library/c_hello_world-hello_world
+Starting tests.
+Output is wrong:
+1c1
+< (null)
+\ No newline at end of file
+---
+> Hello world!
+\ No newline at end of file
+```
+where we see that the execution fails. This will be improved in the future and the actual execution as expected to be
+run by the students will be added.
+
+## The immutable files
+
+There is only one file that should be modified by the students in this example: the `function.c` file. Therefore we can safely
+add all the created files in the `src` except `src/function.c` which is precisely
+the file that the student must modify, as well as the `run.sh` file. The `dojo_assignment.json` file becomes
+```json
+{
+  "dojoAssignmentVersion": 1,
+  "version": 1,
+  "immutable": [
+    {
+      "description": "Dockerfile of the unique container",
+      "path": "Dockerfile",
+      "isDirectory": false
+    },
+    {
+      "description": "The entry point of the Dockerfile",
+      "path": "run.sh",
+      "isDirectory": false
+    },
+    {
+      "description": "The makefile for compilation/execution purposes",
+      "path": "src/Makefile",
+      "isDirectory": false
+    },
+    {
+      "description": "Entry point of the code",
+      "path": "src/hello_world.c",
+      "isDirectory": false
+    },
+    {
+      "description": "The header file fot the program's assignment",
+      "path": "src/function.h",
+      "isDirectory": false
+    },
+    {
+      "description": "The expected output file for comparing with the actual output",
+      "path": "src/expected_output.txt",
+      "isDirectory": false
+    }
+  ],
+  "result": {
+    "container": "hello_world",
+    "volume": "hello_world_volume"
+  }
+}
+```
+
+## The `README.md` file
+
+The `README.md` file is used to provide informations on the assignment and the way the teacher wants students to accomplish
+the assignment and its content is completely free. It is recommended to use the `Markdown` syntax as the
+file extension suggests.
+
+In this assignment the `README.md` file reads
+```markdown
+# Hello world!
+
+C'est le premier vrai exercice jamais créé sur le Dojo!
+
+Il sert de tutoriel pour crΓ©er un exercice simple en C.
+
+## But
+
+Le but est de faire afficher "Hello world!" Γ  notre programme en C.
+
+Pour ce faire, il faut modifier le fichier `src/function.c` sous la ligne
+annotΓ©e avec `TODO`. Bonne chance!
+```
+
+## Publish the work
+
+Now that the assignment is ready, we must publish it. First add/commit/push all the
+files needed for your exercise. In this case, it should be:
+```console
+c_hello_world/
+β”œβ”€β”€ docker-compose.yml
+β”œβ”€β”€ Dockerfile
+β”œβ”€β”€ dojo_assignment.json
+β”œβ”€β”€ README.md
+β”œβ”€β”€ run.sh
+└── src
+    β”œβ”€β”€ expected_output.txt
+    β”œβ”€β”€ function.c
+    β”œβ”€β”€ function.h
+    β”œβ”€β”€ hello_world.c
+    └── Makefile
+```
+Then one must *publish* the assignment for the students to be able to perform to get the exercise.
+
+```bash
+$ dojo assignment publish c_hello_world
+```
+```console
+? Are you sure you want to publish this assignment? Yes
+Please wait while we verify and retrieve data...
+β„Ή Checking Dojo session: 
+    βœ” The session is valid
+β„Ή Checking assignment:
+    β„Ή c_hello_world
+        βœ” The assignment exists
+        βœ” You are in the staff of this assignment
+Please wait while we publish the assignment...
+βœ” Assignment c_hello_world successfully published
+```
+
+The assignment is now ready to be performed by students!
diff --git a/Wiki/UserDocumentation/0-Installation.md b/Wiki/UserDocumentation/0-Installation.md
new file mode 100644
index 0000000000000000000000000000000000000000..da20cbbb4580d83e64ec251bdef712c5cddecb32
--- /dev/null
+++ b/Wiki/UserDocumentation/0-Installation.md
@@ -0,0 +1,38 @@
+# Installation of the Dojo CLI
+
+1. Download the latest stable version (without "-dev" suffix) from the releases: <https://gitedu.hesge.ch/dojo_project/projects/ui/dojocli/-/releases>
+
+![releases](../figures/releases.png)
+
+1. Download the executable corresponding to your OS and architecture.
+   - ℹ️ For these OS you can use specific packaged release that install the binary at the right place (so you can ignore the next point).
+      - **Debian / Ubuntu** : You can use the `deb` package named `Debian / Ubuntu (YOUR_ARCH) package`.
+      - **macOS**: You can use the `pkg` version named `macOS (YOUR_ARCH) package`.
+
+2. Put it in your path. For
+   - For exemple:
+       - ℹ️ **Linux**: `$HOME/.local/bin`
+       - ℹ️ **macOS**: `/usr/local/bin`
+
+3. Verify your installation is working correctly by calling the `dojo` CLI.
+```bash
+dojo
+```
+```console
+Usage: dojo [options] [command]
+
+CLI of the Dojo application
+
+Options:
+  -h, --help           display help for command
+  -H, --host <string>  override the Dojo API endpoint (default: "https://rdps.hesge.ch/dojo/api")
+  -V, --version        output the version number
+
+Commands:
+  assignment           manage an assignment
+  exercise             manage an exercise
+  help [command]       display help for command
+  session              manage Dojo and Gitlab sessions
+```
+
+As you can see calling the `dojo` command shows the help menu.
\ No newline at end of file
diff --git a/Wiki/UserDocumentation/1-Authentification.md b/Wiki/UserDocumentation/1-Authentification.md
new file mode 100644
index 0000000000000000000000000000000000000000..8b1f285d7df035ef9c8eb78da4dba8f26708d69b
--- /dev/null
+++ b/Wiki/UserDocumentation/1-Authentification.md
@@ -0,0 +1,49 @@
+# Authentication to the Dojo
+
+The authentication is done in two steps: login into the dojo app and into https://gitedu.hesge.ch (through an API token).
+
+1.  Login into the dojo application:
+```bash
+dojo session application login --user <email>
+```
+```console
+? Please enter your password [hidden]
+Please wait while we are logging in you to Dojo...
+βœ” Logged in
+    βœ” Teaching staff permissions
+    βœ” Student permissions
+```
+
+2. Register the API token (see below) for Gitlab
+```bash
+dojo session gitlab login <token>
+```
+```console
+Please wait while we are testing your Gitlab token...
+β„Ή Checking Gitlab token: 
+    βœ” Read access
+    βœ” Write access
+```
+The API token can be created by (see <https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html> for more informations):
+
+- Logging into <https://gitedu.hesge.ch>
+- **Preferences -> Access Tokens**
+- Give a name to your token and a validity
+- Tick the **api** box
+- Click the **Create personal access token**
+
+3. Test if it is working
+```bash
+dojo session test
+```
+```console
+β„Ή Checking Dojo session: 
+    βœ” The session is valid
+        βœ” Teaching staff permissions
+        βœ” Student permissions
+β„Ή Checking Gitlab token: 
+    βœ” Read access
+    βœ” Write access
+```
+
+Good news. You can use the Dojo!
diff --git a/Wiki/UserDocumentation/2-Assignment-creation.md b/Wiki/UserDocumentation/2-Assignment-creation.md
new file mode 100644
index 0000000000000000000000000000000000000000..15c7392aaaa51cc1a762e9c2e0600ecf4577ae1d
--- /dev/null
+++ b/Wiki/UserDocumentation/2-Assignment-creation.md
@@ -0,0 +1,66 @@
+# Assignment creation
+
+The assignment is created by a member of the teaching staff and is the basis for students to perform their exercise.
+
+1. To create an assignment
+```bash
+dojo assignment create --name <unique_name>
+```
+```console
+Please wait while we verify and retrieve data...
+β„Ή Checking Dojo session: 
+    βœ” The session is valid
+        βœ” Teaching staff permissions
+β„Ή Checking Gitlab token: 
+    βœ” Read access
+    βœ” Write access
+βœ” Assignment name "unique_name" is available
+Please wait while we are creating the assignment...
+βœ” Assignment successfully created
+    β„Ή Name: unique_name
+    β„Ή Web URL: https://gitedu.hesge.ch/dojo/assignment/unique_name
+    β„Ή HTTP Repo: https://gitedu.hesge.ch/dojo/assignment/unique_name.git
+    β„Ή SSH Repo: ssh://git@ssh.hesge.ch:10572/dojo/assignment/unique_name.git
+```
+where `<unique_name>` is the name of the assignment. By default only the creator of the exercise is added to
+the assignment (which is just a git repository with some configuration files in it).
+There are several other options that can be provided:
+```bash
+dojo assignment create --name <unique_name> --template <url>
+```
+where `<url>` is the url of the template repository one may want to use as a basis for the assignment-
+```bash
+dojo assignment create --name <unique_name> --members_username <usernames>
+```
+where `<usernames>` is a list of gitedu usernames that will be given the same permissions as the
+user creating the assignment.
+
+As usual one can show the help menu by typing
+```bash
+dojo assignment create --help
+```
+Or you may just enter (`--help` is implicit in most commands)
+```bash
+dojo assignment create
+```
+2. Clone the repository of the assignment that was just created:
+```bash
+git clone ssh://git@ssh.hesge.ch:10572/dojo/assignment/unique_name.git
+```
+3. Modify the `unique_name` assignment as you want (modify the Dockerfile, docker-compose.yml files, add a readme, source code, compilation tools, etc.). Commit and push our work (soonβ„’ more details will be provided on how to create assignment).
+4. Once the assignment is done it must be published to be available to students:
+```bash
+dojo assignment publish unique_name
+```
+```console
+? Are you sure you want to publish this assignment? Yes
+Please wait while we verify and retrieve data...
+β„Ή Checking Dojo session: 
+    βœ” The session is valid
+β„Ή Checking assignment:
+    β„Ή unique_name
+        βœ” The assignment exists
+        βœ” You are in the staff of this assignment
+Please wait while we publish the assignment...
+βœ” Assignment unique_name successfully published
+```
\ No newline at end of file
diff --git a/Wiki/UserDocumentation/3-Exercise-creation.md b/Wiki/UserDocumentation/3-Exercise-creation.md
new file mode 100644
index 0000000000000000000000000000000000000000..29817fb37e5441833e1c0da61b9f41557d6d0c2e
--- /dev/null
+++ b/Wiki/UserDocumentation/3-Exercise-creation.md
@@ -0,0 +1,74 @@
+# Exercise creation
+
+The exercise is an instance of a **published assignment** to be performed by students (or group of students).
+
+1. Create an exercise
+```bash
+dojo exercise create --assignment unique_name                   
+```
+```console
+Please wait while we verify and retrieve data...
+β„Ή Checking Dojo session: 
+    βœ” The session is valid
+        βœ” Student permissions
+β„Ή Checking Gitlab token: 
+    βœ” Read access
+    βœ” Write access
+β„Ή Checking assignment:
+    βœ” Assignment "unique_name" exists
+    βœ” Assignment "unique_name" is published
+Please wait while we are creating the exercise...
+βœ” Exercise successfully created
+    β„Ή Id: some-long-hash
+    β„Ή Name: DojoEx - unique_name - your.name
+    β„Ή Web URL: https://gitedu.hesge.ch/dojo/exercise/dojo-ex_unique_name_some-long-hash
+    β„Ή HTTP Repo: https://gitedu.hesge.ch/dojo/exercise/dojo-ex_unique_name_some-long-hash.git
+    β„Ή SSH Repo: ssh://git@ssh.hesge.ch:10572/dojo/exercise/dojo-ex_unique_name_some-long-hash.git
+```
+**Tips**: You cas use the --members_username or --members_id options to add other students of the group to the exercise.
+2. Make changes and try solving the exercise.
+3. The complete tests can be run with the following command.
+```bash
+dojo exercise run
+```
+```console
+Please wait while we are checking and creating dependencies...
+    β„Ή Checking exercise content:
+        βœ” The exercise folder contains all the needed files
+        βœ” The dojo_assignment.json file is valid
+    βœ” The Docker deamon is running
+Please wait while we are running the exercise...
+    βœ” Docker Compose file run successfully
+    βœ” Linked services logs acquired
+    βœ” Containers stopped and removed
+Please wait while we are checking the results...
+    βœ” Results file found
+    βœ” Results file is valid
+    βœ” Results folder size is in bounds
+
+   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Results ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+   ┃                                                                                                    ┃
+   ┃   Global result : βœ… Success                                                                       ┃
+   ┃                                                                                                    ┃
+   ┃   Execution exit code : 0                                                                          ┃
+   ┃                                                                                                    ┃
+   ┃   Tests passed : 3                                                                                 ┃
+   ┃   Tests failed : 1                                                                                 ┃
+   ┃                                                                                                    ┃
+   ┃   Tests :                                                                                          ┃
+   ┃   - βœ… ListeOrdonnee                                                                               ┃
+   ┃   - βœ… ListeVide                                                                                   ┃
+   ┃   - βœ… ListeOrdreInverse                                                                           ┃
+   ┃   - ❌ ListeRandom                                                                                 ┃
+   ┃                                                                                                    ┃
+   ┃   Execution results folder : /home/username/DojoExecutions/dojo_execLogs_2023-08-21T21_33_38_684Z  ┃
+   ┃                                                                                                    ┃
+   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+```
+This command runs the exercise in the current directory or in the path provided by the `--path` option.
+
+4. Once confident enough in the solution, one can commit/push the solution. 
+This triggers the CI/CD pipeline on gitedu. In the CI/CD all immutable files are overwritten and 
+the docker-compose is executed (only logs from the current container are given) then other logs 
+are retrieved from the other images that may be used. The error code of the docker container is retrieved. 
+
diff --git a/Wiki/figures/releases.png b/Wiki/figures/releases.png
new file mode 100644
index 0000000000000000000000000000000000000000..8950a930ee305be9aeb50317502a57d90ce2d853
Binary files /dev/null and b/Wiki/figures/releases.png differ
diff --git a/Wiki/home.md b/Wiki/home.md
new file mode 100644
index 0000000000000000000000000000000000000000..90b298e88fc361293cfa24c148149689e3cd9fa6
--- /dev/null
+++ b/Wiki/home.md
@@ -0,0 +1,25 @@
+# Documentation of the `dojo` CLI utility
+
+In this wiki you will find the documentation related to the `dojo` CLI.
+
+## Dojo Project
+The dojo platform is an online tool built to help practice programming by allowing users to propose assignments and perform them as exercises.
+
+The two major concepts of the platform are the **assignments** (provided by teaching staff) and the **exercises** (performed by students).
+
+More details here : [Dojo detailed presentation](0-Dojo-presentation)
+
+## User documentation
+
+* [Installation of the CLI](UserDocumentation/0-Installation)
+* [Authentification](UserDocumentation/1-Authentification)
+* [Assignment creation](UserDocumentation/2-Assignment-creation)
+* [Exercice creation](UserDocumentation/3-Exercise-creation)
+
+## Tutorials / Exemples
+
+### Students / Everyone
+* [How to perform an exercise](Tutorials/0-Exercise-perform)
+
+### Teaching staff
+* [How to create and publish an assignment](Tutorials/1-Assignment-creation)