commit af661cf543921fab3e6e904290419d27d6f57c9b Author: Chneemann Date: Sun May 12 11:57:51 2024 +0200 first commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..59d9a3a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e11b341 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db + +# Firebase +.firebase +*-debug.log +.runtimeconfig.json +/src/app/environments/config.ts \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..77b3745 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 + "recommendations": ["angular.ng-template"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..925af83 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "ng serve", + "type": "chrome", + "request": "launch", + "preLaunchTask": "npm: start", + "url": "http://localhost:4200/" + }, + { + "name": "ng test", + "type": "chrome", + "request": "launch", + "preLaunchTask": "npm: test", + "url": "http://localhost:9876/debug.html" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a298b5b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "start", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "pattern": "$tsc", + "background": { + "activeOnStart": true, + "beginsPattern": { + "regexp": "(.*?)" + }, + "endsPattern": { + "regexp": "bundle generation complete" + } + } + } + }, + { + "type": "npm", + "script": "test", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "pattern": "$tsc", + "background": { + "activeOnStart": true, + "beginsPattern": { + "regexp": "(.*?)" + }, + "endsPattern": { + "regexp": "bundle generation complete" + } + } + } + } + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..2431214 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Dabubble + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.2.1. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/angular.json b/angular.json new file mode 100644 index 0000000..59051f4 --- /dev/null +++ b/angular.json @@ -0,0 +1,92 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "dabubble": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": "dist/dabubble", + "index": "src/index.html", + "browser": "src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": ["src/favicon.ico", "src/assets"], + "styles": [ + "src/styles.scss", + "./node_modules/@ctrl/ngx-emoji-mart/picker.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "4mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "16kb", + "maximumError": "32kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "dabubble:build:production" + }, + "development": { + "buildTarget": "dabubble:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "dabubble:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": ["zone.js", "zone.js/testing"], + "tsConfig": "tsconfig.spec.json", + "inlineStyleLanguage": "scss", + "assets": ["src/favicon.ico", "src/assets"], + "styles": [ + "src/styles.scss", + "./node_modules/@ctrl/ngx-emoji-mart/picker.css" + ], + "scripts": [] + } + } + } + } + } +} diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/firebase.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0f09c59 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13515 @@ +{ + "name": "dabubble", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dabubble", + "version": "0.0.0", + "dependencies": { + "@angular/animations": "^17.2.0", + "@angular/cdk": "^17.3.1", + "@angular/common": "^17.2.0", + "@angular/compiler": "^17.2.0", + "@angular/core": "^17.2.0", + "@angular/fire": "^17.0.1", + "@angular/forms": "^17.2.0", + "@angular/platform-browser": "^17.2.0", + "@angular/platform-browser-dynamic": "^17.2.0", + "@angular/router": "^17.2.0", + "@ctrl/ngx-emoji-mart": "^9.2.0", + "@ngx-translate/core": "^15.0.0", + "@ngx-translate/http-loader": "^8.0.0", + "ng2-pdf-viewer": "^10.0.0", + "ngx-extended-pdf-viewer": "^19.6.6", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.14.3" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^17.2.1", + "@angular/cli": "^17.2.1", + "@angular/compiler-cli": "^17.2.0", + "@types/jasmine": "~5.1.0", + "jasmine-core": "~5.1.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.3.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1703.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1703.2.tgz", + "integrity": "sha512-fT5gSzwDHOyGv8zF97t8rjeoYSGSxXjWWstl3rN1nXdO0qgJ5m6Sv0fupON+HltdXDCBLRH+2khNpqx/Fh0Qww==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "17.3.2", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "17.3.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.3.2.tgz", + "integrity": "sha512-muPCUyL0uHvRkLH4NLWiccER6P2vCm/Q5DDvqyN4XOzzY3tAHHLrKrpvY87sgd2oNJ6Ci8x7GPNcfzR5KELCnw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1703.2", + "@angular-devkit/build-webpack": "0.1703.2", + "@angular-devkit/core": "17.3.2", + "@babel/core": "7.24.0", + "@babel/generator": "7.23.6", + "@babel/helper-annotate-as-pure": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", + "@babel/plugin-transform-async-generator-functions": "7.23.9", + "@babel/plugin-transform-async-to-generator": "7.23.3", + "@babel/plugin-transform-runtime": "7.24.0", + "@babel/preset-env": "7.24.0", + "@babel/runtime": "7.24.0", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "17.3.2", + "@vitejs/plugin-basic-ssl": "1.1.0", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.18", + "babel-loader": "9.1.3", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.21.5", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.22", + "css-loader": "6.10.0", + "esbuild-wasm": "0.20.1", + "fast-glob": "3.3.2", + "http-proxy-middleware": "2.0.6", + "https-proxy-agent": "7.0.4", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "karma-source-map-support": "1.4.0", + "less": "4.2.0", + "less-loader": "11.1.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "magic-string": "0.30.8", + "mini-css-extract-plugin": "2.8.1", + "mrmime": "2.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.1", + "piscina": "4.4.0", + "postcss": "8.4.35", + "postcss-loader": "8.1.1", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.1", + "sass": "1.71.1", + "sass-loader": "14.1.1", + "semver": "7.6.0", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "terser": "5.29.1", + "tree-kill": "1.2.2", + "tslib": "2.6.2", + "undici": "6.7.1", + "vite": "5.1.5", + "watchpack": "2.4.0", + "webpack": "5.90.3", + "webpack-dev-middleware": "6.1.2", + "webpack-dev-server": "4.15.1", + "webpack-merge": "5.10.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.20.1" + }, + "peerDependencies": { + "@angular/compiler-cli": "^17.0.0", + "@angular/localize": "^17.0.0", + "@angular/platform-server": "^17.0.0", + "@angular/service-worker": "^17.0.0", + "@web/test-runner": "^0.18.0", + "browser-sync": "^3.0.2", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "karma": "^6.3.0", + "ng-packagr": "^17.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=5.2 <5.5" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1703.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1703.2.tgz", + "integrity": "sha512-w7rVFQcZK4iTCd/MLfQWIkDkwBOfAs++txNQyS9qYID8KvLs1V+oWYd2qDBRelRv1u3YtaCIS1pQx3GFKBC3OA==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1703.2", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "17.3.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.2.tgz", + "integrity": "sha512-1vxKo9+pdSwTOwqPDSYQh84gZYmCJo6OgR5+AZoGLGMZSeqvi9RG5RiUcOMLQYOnuYv0arlhlWxz0ZjyR8ApKw==", + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "17.3.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.2.tgz", + "integrity": "sha512-AYO6oc6QpFGigc1KiDzEVT1CeLnwvnIedU5Q/U3JDZ/Yqmvgc09D64g9XXER2kg6tV7iEgLxiYnonIAQOHq7eA==", + "dependencies": { + "@angular-devkit/core": "17.3.2", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/animations": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.3.1.tgz", + "integrity": "sha512-2TZ0M5J0IizhHpb404DeqArlv8Ki9BFz5ZUuET2uFROpKW8IMDCht8fSrn/DKHpjB9lvzPUhNFaRxNWEY6klnA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.1" + } + }, + "node_modules/@angular/cdk": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.3.1.tgz", + "integrity": "sha512-pHSN+KlCmdo2u9jY7Yxsry/ZK+EcjOYGzdwxXxcKragMzm7etY3BJiTl4N+qZRuV6cJlMj2PRkij8ABi/HQdEA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^7.1.2" + }, + "peerDependencies": { + "@angular/common": "^17.0.0 || ^18.0.0", + "@angular/core": "^17.0.0 || ^18.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "17.3.2", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.3.2.tgz", + "integrity": "sha512-g6r4XZyGnh9P6GmWgaFh8RmR4L6UdQ408e3SpG3rjncuPRD57Ur8806GfCLPt6HIA9TARiKmaJ0EJ3RsIjag0g==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1703.2", + "@angular-devkit/core": "17.3.2", + "@angular-devkit/schematics": "17.3.2", + "@schematics/angular": "17.3.2", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "4.1.2", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "npm-package-arg": "11.0.1", + "npm-pick-manifest": "9.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "pacote": "17.0.6", + "resolve": "1.22.8", + "semver": "7.6.0", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.1.tgz", + "integrity": "sha512-HyUTJ4RxhE3bOmFRV6Fv2y01ixbrUb8Hd4MxPm8REbNMGKsWCfXhR3FfxFL18Sc03SAF+o0Md0wwekjFKTNKfQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.3.1.tgz", + "integrity": "sha512-8qqlWPGZEyD2FY5losOW3Aocro+lFysPDzsf0LHgQUM6Ub1b+pq4jUOjH6w0vzaxG3TfxkgzOQ9aNdWtSV67Rg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.1" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.3.1.tgz", + "integrity": "sha512-xLV9KU+zOpe57/2rQ59ku21EaStNpLSlR9+qkDYf8JR09fB+W9vY3UYbpi5RjHxAFIZBM5D9SFQjjll8rch26g==", + "dev": true, + "dependencies": { + "@babel/core": "7.23.9", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/index.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/compiler": "17.3.1", + "typescript": ">=5.2 <5.5" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/core": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.1.tgz", + "integrity": "sha512-Qf3/sgkXS1LHwOTtqAVYprySrn0YpPIZqerPc0tK+hyQfwAz5BQlpcBhbH8RWKlfCY8eO0cqo/j0+e8DQOgYfg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.14.0" + } + }, + "node_modules/@angular/fire": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/@angular/fire/-/fire-17.0.1.tgz", + "integrity": "sha512-bhbogL4m50AKzSVn4kdZX3/2XrYTMvpsgP/4xnTPuMoTFgOrjV24CDc+1lOL+Z0QXRIupj84/Pg4KNFD4lXXzQ==", + "dependencies": { + "@angular-devkit/schematics": "^17.0.0", + "@schematics/angular": "^17.0.0", + "firebase": "^10.7.0", + "fs-extra": "^8.0.1", + "fuzzy": "^0.1.3", + "inquirer": "^8.1.1", + "inquirer-autocomplete-prompt": "^1.0.1", + "jsonc-parser": "^3.0.0", + "node-fetch": "^2.6.1", + "open": "^8.0.0", + "ora": "^5.3.0", + "rxfire": "^6.0.5", + "semver": "^7.1.3", + "triple-beam": "^1.3.0", + "tslib": "^2.3.0", + "winston": "^3.0.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0", + "@angular/platform-browser": "^17.0.0", + "@angular/platform-browser-dynamic": "^17.0.0", + "firebase-tools": "^13.0.0", + "rxjs": "~7.8.0" + }, + "peerDependenciesMeta": { + "firebase-tools": { + "optional": true + } + } + }, + "node_modules/@angular/fire/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular/fire/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@angular/fire/node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@angular/fire/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@angular/fire/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@angular/fire/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/fire/node_modules/inquirer": { + "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", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@angular/fire/node_modules/inquirer-autocomplete-prompt": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-1.4.0.tgz", + "integrity": "sha512-qHgHyJmbULt4hI+kCmwX92MnSxDs/Yhdt4wPA30qnoa01OF6uTXV8yvH4hKXgdaTNmkZ9D01MHjqKYEuJN+ONw==", + "dependencies": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "figures": "^3.2.0", + "run-async": "^2.4.0", + "rxjs": "^6.6.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "inquirer": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@angular/fire/node_modules/inquirer-autocomplete-prompt/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular/fire/node_modules/inquirer-autocomplete-prompt/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@angular/fire/node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "node_modules/@angular/fire/node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/@angular/fire/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/forms": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.3.1.tgz", + "integrity": "sha512-HndsO90k67sFHzd+sII+rhAUksffBvquFuAUCc6QR9WVjILxVg2fY7oBidgS1gKNqu0mptPG0GvuORnaW/0gSg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.1", + "@angular/core": "17.3.1", + "@angular/platform-browser": "17.3.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.1.tgz", + "integrity": "sha512-8ABAL8PElSGzkIparVwifsU0NSu0DdqnWYw9YvLhhZQ6lOuWbG+dTUo/DXzmWhA6ezQWJGNakEZPJJytFIIy+A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/animations": "17.3.1", + "@angular/common": "17.3.1", + "@angular/core": "17.3.1" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.3.1.tgz", + "integrity": "sha512-ACW/npNaDxUNQtEomjjv/KIBY8jHEinePff5qosnAxLE0IpA4qE9eDp36zG35xoJqrPJPYjXbZCBRqqrzM7U7Q==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.1", + "@angular/compiler": "17.3.1", + "@angular/core": "17.3.1", + "@angular/platform-browser": "17.3.1" + } + }, + "node_modules/@angular/router": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.3.1.tgz", + "integrity": "sha512-H6H7lY9i5Ppu0SFwwpeWqJbCFw8cILOj8Rd1+AGoCN5m3ivPtjD2Ltz62PI2zZkqx+WhQdk19l61Wm3oRqg70A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.1", + "@angular/core": "17.3.1", + "@angular/platform-browser": "17.3.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", + "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", + "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", + "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.0.tgz", + "integrity": "sha512-zc0GA5IitLKJrSfXlXmp8KDqLrnGECK7YRfQBmEKg1NmBOQ7e+KuclBEKJgzifQeUYLdNiAw4B4bjyvzWVLiSA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", + "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.24.0", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@ctrl/ngx-emoji-mart": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/ngx-emoji-mart/-/ngx-emoji-mart-9.2.0.tgz", + "integrity": "sha512-q8B7DiXPfyTe+VOGO6Ix7eh5gKCuADxAsud2xXRTlECTfchoKGTmirSczyjaxIKE/xmB+/ZsnkpthZqUM7SAJQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": ">=15.0.0-0" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.1.tgz", + "integrity": "sha512-5mnH1aQa99J5lZMJwTNzIoRc4yGXHf+fOn+EoEWhCDA3XGPweGHcylCbqq+G1wVJmfILL57fohDMa8ftMZ+44g==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/installations": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.7.tgz", + "integrity": "sha512-17VCly4P0VFBDqaaal7m1nhyYQwsygtaTpSsnc51sFPRrr9XIYtnD8ficon9fneEGEoJQ2g7OtASvhwX9EbK8g==", + "dependencies": { + "@firebase/analytics": "0.10.1", + "@firebase/analytics-types": "0.8.0", + "@firebase/component": "0.6.5", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.0.tgz", + "integrity": "sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==" + }, + "node_modules/@firebase/app": { + "version": "0.9.29", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.29.tgz", + "integrity": "sha512-HbKTjfmILklasIu/ij6zKnFf3SgLYXkBDVN7leJfVGmohl+zA7Ig+eXM1ZkT1pyBJ8FTYR+mlOJer/lNEnUCtw==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "idb": "7.1.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.2.tgz", + "integrity": "sha512-A2B5+ldOguYAeqW1quFN5qNdruSNRrg4W59ag1Eq6QzxuHNIkrE+TrapfrW/z5NYFjCxAYqr/unVCgmk80Dwcg==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.9.tgz", + "integrity": "sha512-7LxyupQ8XeEHRh72mO+tqm69kHT6KbWi2KtFMGedJ6tNbwzFzojcXESMKN8RpADXbYoQgY3loWMJjMx4r2Zt7w==", + "dependencies": { + "@firebase/app-check": "0.8.2", + "@firebase/app-check-types": "0.5.0", + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.0.tgz", + "integrity": "sha512-xAxHPZPIgFXnI+vb4sbBjZcde7ZluzPPaSK7Lx3/nmuVk4TjZvnL8ONnkd4ERQKL8WePQySU+pRcWkh8rDf5Sg==" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.0.tgz", + "integrity": "sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==" + }, + "node_modules/@firebase/app-compat": { + "version": "0.2.29", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.29.tgz", + "integrity": "sha512-NqUdegXJfwphx9i/2bOE2CTZ55TC9bbDg+iwkxVShsPBJhD3CzQJkFhoDz4ccfbJaKZGsqjY3fisgX5kbDROnA==", + "dependencies": { + "@firebase/app": "0.9.29", + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", + "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + }, + "node_modules/@firebase/auth": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.6.2.tgz", + "integrity": "sha512-BFo/Nj1AAbKLbFiUyXCcnT/bSqMJicFOgdTAKzlXvCul7+eUE29vWmzd1g59O3iKAxvv3+fbQYjQVJpNTTHIyw==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0", + "undici": "5.28.3" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.4.tgz", + "integrity": "sha512-EtRVW9s0YsuJv3GnOGDoLUW3Pp9f3HcqWA2WK92E30Qa0FEVRwCSRLVQwn9td+SLVY3AP9gi/auC1q3osd4yCg==", + "dependencies": { + "@firebase/auth": "1.6.2", + "@firebase/auth-types": "0.12.0", + "@firebase/component": "0.6.5", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0", + "undici": "5.28.3" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-compat/node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", + "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + }, + "node_modules/@firebase/auth-types": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.0.tgz", + "integrity": "sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/auth/node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.5.tgz", + "integrity": "sha512-2tVDk1ixi12sbDmmfITK8lxSjmcb73BMF6Qwc3U44hN/J1Fi1QY/Hnnb6klFlbB9/G16a3J3d4nXykye2EADTw==", + "dependencies": { + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.3.tgz", + "integrity": "sha512-9fjqLt9JzL46gw9+NRqsgQEMjgRwfd8XtzcKqG+UYyhVeFCdVRQ0Wp6Dw/dvYHnbH5vNEKzNv36dcB4p+PIAAA==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.0", + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.3.tgz", + "integrity": "sha512-7tHEOcMbK5jJzHWyphPux4osogH/adWwncxdMxdBpB9g1DNIyY4dcz1oJdlkXGM/i/AjUBesZsd5CuwTRTBNTw==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/database": "1.0.3", + "@firebase/database-types": "1.0.1", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.1.tgz", + "integrity": "sha512-Tmcmx5XgiI7UVF/4oGg2P3AOTfq3WKEPsm2yf+uXtN7uG/a4WTWhVMrXGYRY2ZUL1xPxv9V33wQRJ+CcrUhVXw==", + "dependencies": { + "@firebase/app-types": "0.9.0", + "@firebase/util": "1.9.4" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.5.0.tgz", + "integrity": "sha512-rXS6v4HbsN6vZQlq2fLW1ZHb+J5SnS+8Zqb/McbKFIrGYjPUZo5CyO75mkgtlR1tCYAwCebaqoEWb6JHgZv/ww==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "@firebase/webchannel-wrapper": "0.10.5", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0", + "undici": "5.28.3" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.27", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.27.tgz", + "integrity": "sha512-gY2q0fCDJvPg/IurZQbBM7MIVjxA1/LsvfgFOubUTrex5KTY9qm4/2V2R79eAs8Q+b4B8soDtlEjk6L8BW1Crw==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/firestore": "4.5.0", + "@firebase/firestore-types": "3.0.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.0.tgz", + "integrity": "sha512-Meg4cIezHo9zLamw0ymFYBD4SMjLb+ZXIbuN7T7ddXN6MGoICmOTq3/ltdCGoDCS2u+H1XJs2u/cYp75jsX9Qw==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/firestore/node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@firebase/functions": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.2.tgz", + "integrity": "sha512-2NULTYOZbu0rXczwfYdqQH0w1FmmYrKjTy1YPQSHLCAkMBdfewoKmVm4Lyo2vRn0H9ZndciLY7NszKDFt9MKCQ==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.0", + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.5", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0", + "undici": "5.28.3" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.8.tgz", + "integrity": "sha512-VDHSw6UOu8RxfgAY/q8e+Jn+9Fh60Fc28yck0yfMsi2e0BiWgonIMWkFspFGGLgOJebTHl+hc+9v91rhzU6xlg==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/functions": "0.11.2", + "@firebase/functions-types": "0.6.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.0.tgz", + "integrity": "sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==" + }, + "node_modules/@firebase/functions/node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@firebase/installations": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.5.tgz", + "integrity": "sha512-0xxnQWw8rSRzu0ZOCkZaO+MJ0LkDAfwwTB2Z1SxRK6FAz5xkxD1ZUwM0WbCRni49PKubCrZYOJ6yg7tSjU7AKA==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/util": "1.9.4", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.5.tgz", + "integrity": "sha512-usvoIaog5CHEw082HXLrKAZ1qd4hIC3N/LDe2NqBgI3pkGE/7auLVM4Gn5gvyryp0x8z/IP1+d9fkGUj2OaGLQ==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/installations": "0.6.5", + "@firebase/installations-types": "0.5.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.0.tgz", + "integrity": "sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", + "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.6", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.6.tgz", + "integrity": "sha512-IORsPp9IPWq4j4yEhTOZ6GAGi3gQwGc+4yexmTAlya+qeBRSdRnJg2iIU/aj+tcKDQYr9RQuQPgHHOdFIx//vA==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/installations": "0.6.5", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.4", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.6.tgz", + "integrity": "sha512-Q2xC1s4L7Vpss7P7Gy6GuIS+xmJrf/vm9+gX76IK1Bo1TjoKwleCLHt1LHkPz5Rvqg5pTgzzI8qqPhBpZosFCg==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/messaging": "0.12.6", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz", + "integrity": "sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==" + }, + "node_modules/@firebase/performance": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.5.tgz", + "integrity": "sha512-OzAGcWhOqEFH9GdwUuY0oC5FSlnMejcnmSAhR+EjpI7exdDvixyLyCR4txjSHYNTbumrFBG+EP8GO11CNXRaJA==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/installations": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.5.tgz", + "integrity": "sha512-jJwJkVyDcIMBaVGrZ6CRGs4m5FCZsWB5QCWYI3FdsHyIa9/TfteNDilxj9wGciF2naFIHDW7TgE69U5dAH9Ktg==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/performance": "0.6.5", + "@firebase/performance-types": "0.2.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.0.tgz", + "integrity": "sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==" + }, + "node_modules/@firebase/remote-config": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.5.tgz", + "integrity": "sha512-rGLqc/4OmxrS39RA9kgwa6JmgWytQuMo+B8pFhmGp3d++x2Hf9j+MLQfhOLyyUo64fNw20J19mLXhrXvKHsjZQ==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/installations": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.5.tgz", + "integrity": "sha512-ImkNnLuGrD/bylBHDJigSY6LMwRrwt37wQbsGZhWG4QQ6KLzHzSf0nnFRRFvkOZodEUE57Ib8l74d6Yn/6TDUQ==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/logger": "0.4.0", + "@firebase/remote-config": "0.4.5", + "@firebase/remote-config-types": "0.3.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz", + "integrity": "sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==" + }, + "node_modules/@firebase/storage": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.2.tgz", + "integrity": "sha512-MzanOBcxDx9oOwDaDPMuiYxd6CxcN1xZm+os5uNE3C1itbRKLhM9rzpODDKWzcbnHHFtXk3Q3lsK/d3Xa1WYYw==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0", + "undici": "5.28.3" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.5.tgz", + "integrity": "sha512-5dJXfY5NxCF5NAk4dLvJqC+m6cgcf0Fr29nrMHwhwI34pBheQq2PdRZqALsqZCES9dnHTuFNlqGQDpLr+Ph4rw==", + "dependencies": { + "@firebase/component": "0.6.5", + "@firebase/storage": "0.12.2", + "@firebase/storage-types": "0.8.0", + "@firebase/util": "1.9.4", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.0.tgz", + "integrity": "sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/storage/node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@firebase/util": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.4.tgz", + "integrity": "sha512-WLonYmS1FGHT97TsUmRN3qnTh5TeeoJp1Gg5fithzuAgdZOUtsYECfy7/noQ3llaguios8r5BuXSEiK82+UrxQ==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.5.tgz", + "integrity": "sha512-eSkJsnhBWv5kCTSU1tSUVl9mpFu+5NXXunZc83le8GMjMlsWwQArSc7cJJ4yl+aDFY0NGLi0AjZWMn1axOrkRg==" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.14", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz", + "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.11.tgz", + "integrity": "sha512-amjhSfJ+xYnTP+hncJMmkchoRtjIdi+uO3FaymGSCr07yu5xfpXFEnhZkTU1mj2lPJB3oVToau7j9YkqB+YNdg==", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@ngtools/webpack": { + "version": "17.3.2", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.3.2.tgz", + "integrity": "sha512-E8zejFF4aJ8l2XcF+GgnE/1IqsZepnPT1xzulLB4LXtjVuXLFLoF9xkHQwxs7cJWWZsxd/SlNsCIcn/ezrYBcQ==", + "dev": true, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^17.0.0", + "typescript": ">=5.2 <5.5", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-translate/core": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz", + "integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==", + "engines": { + "node": "^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "rxjs": "^6.5.5 || ^7.4.0" + } + }, + "node_modules/@ngx-translate/http-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-8.0.0.tgz", + "integrity": "sha512-SFMsdUcmHF5OdZkL1CHEoSAwbP5EbAOPTLLboOCRRoOg21P4GJx+51jxGdJeGve6LSKLf4Pay7BkTwmE6vxYlg==", + "engines": { + "node": "^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "@ngx-translate/core": ">=15.0.0", + "rxjs": "^6.5.5 || ^7.4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", + "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/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/@npmcli/package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", + "dev": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@schematics/angular": { + "version": "17.3.2", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.2.tgz", + "integrity": "sha512-zPINvow0Qo6ionnDl25ZzSSLDyDxBjqRPEJWGHU70expbjXK4A2caQT9P/8ImhapbJAXJCfxg4GF9z1d/sWe4w==", + "dependencies": { + "@angular-devkit/core": "17.3.2", + "@angular-devkit/schematics": "17.3.2", + "jsonc-parser": "3.2.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@sigstore/bundle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", + "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", + "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.3.tgz", + "integrity": "sha512-LqlA+ffyN02yC7RKszCdMTS6bldZnIodiox+IkT8B2f8oRYXCB3LQ9roXeiEL21m64CVH1wyveYAORfD65WoSw==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.2.tgz", + "integrity": "sha512-mwbY1VrEGU4CO55t+Kl6I7WZzIl+ysSzEYdA1Nv/FTrl2bkeaPXo5PnWZAVfcY2zSdhOpsUTJW67/M2zHXGn5w==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0", + "tuf-js": "^2.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.1.1.tgz", + "integrity": "sha512-BNANJms49rw9Q5J+fJjrDqOQSzjXDcOq/pgKDaVdDoIvQwqIfaoUriy+fQfh8sBX04hr4bkkrwu3EbhQqoQH7A==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", + "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/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/@tufjs/models/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.6.tgz", + "integrity": "sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.4.tgz", + "integrity": "sha512-px7OMFO/ncXxixDe1zR13V1iycqWae0MxTaw62RpFlksUi5QuNWgQJFkTQjIOvrmutJbI7Fp2Y2N1F6D2R4G6w==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "dev": true, + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "devOptional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/autoprefixer": { + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "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", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "devOptional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "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", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "devOptional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/cacache/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/cacache/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "devOptional": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "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/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", + "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/critters": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", + "integrity": "sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "postcss-media-query-parser": "^0.2.3" + } + }, + "node_modules/critters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/critters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/critters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/critters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/critters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/critters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/cross-spawn/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/css-loader": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/dommatrix": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dommatrix/-/dommatrix-1.0.3.tgz", + "integrity": "sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==", + "deprecated": "dommatrix is no longer maintained. Please use @thednp/dommatrix." + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.717", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz", + "integrity": "sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "devOptional": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "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/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.1.tgz", + "integrity": "sha512-6v/WJubRsjxBbQdz6izgvx7LsVFvVaGmSdwrFHmEzoVgfXL89hkKPoQHsnVI2ngOkcBUQT9kmAM1hVL1k/Av4A==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.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/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "devOptional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/firebase": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.9.0.tgz", + "integrity": "sha512-R8rDU3mg2dq0uPOoZ5Nc3BeZTbXxBPJS8HcZLtnV0f5/YrmpNsHngzmMHRVB+91T+ViJGVL/42dV23gS9w9ccw==", + "dependencies": { + "@firebase/analytics": "0.10.1", + "@firebase/analytics-compat": "0.2.7", + "@firebase/app": "0.9.29", + "@firebase/app-check": "0.8.2", + "@firebase/app-check-compat": "0.3.9", + "@firebase/app-compat": "0.2.29", + "@firebase/app-types": "0.9.0", + "@firebase/auth": "1.6.2", + "@firebase/auth-compat": "0.5.4", + "@firebase/database": "1.0.3", + "@firebase/database-compat": "1.0.3", + "@firebase/firestore": "4.5.0", + "@firebase/firestore-compat": "0.3.27", + "@firebase/functions": "0.11.2", + "@firebase/functions-compat": "0.3.8", + "@firebase/installations": "0.6.5", + "@firebase/installations-compat": "0.2.5", + "@firebase/messaging": "0.12.6", + "@firebase/messaging-compat": "0.2.6", + "@firebase/performance": "0.6.5", + "@firebase/performance-compat": "0.2.5", + "@firebase/remote-config": "0.4.5", + "@firebase/remote-config-compat": "0.2.5", + "@firebase/storage": "0.12.2", + "@firebase/storage-compat": "0.3.5", + "@firebase/util": "1.9.4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuzzy": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", + "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "devOptional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/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/ignore-walk/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "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/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", + "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "9.2.15", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", + "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "dev": true, + "dependencies": { + "@ljharb/through": "^2.3.12", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^3.2.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "devOptional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "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==", + "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", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "devOptional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "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", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "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==", + "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/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "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/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jasmine-core": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.2.tgz", + "integrity": "sha512-2oIUMGn00FdUiqz6epiiJr7xcFyNYj3rDcfmnzfkBnHyBQ3cBQUs4mmyGsOb7TTLb9kxk7dBcmEmqhDKkBoDyA==", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/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/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "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/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/karma": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", + "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", + "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "dependencies": { + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", + "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": "^4.0.0 || ^5.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" + } + }, + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", + "integrity": "sha512-O236+gd0ZXS8YAjFx8xKaJ94/erqUliEkJTDedyE7iHvv4ZVqi+q+8acJxu05/WJDKm512EUNn809In37nWlAQ==", + "dev": true + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/karma/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/karma/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/karma/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", + "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.deburr": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", + "integrity": "sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/logform": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", + "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "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", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/ng2-pdf-viewer": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-10.0.0.tgz", + "integrity": "sha512-zEefcAsTpDoxFceQYs3ycPMaUAkt5UX4OcTstVQoNqRK6w+vOY+V8z8aFCuBwnt+7iN1EHaIpquOf4S9mWc04g==", + "dependencies": { + "pdfjs-dist": "~2.16.105", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "pdfjs-dist": "~2.16.105" + } + }, + "node_modules/ngx-extended-pdf-viewer": { + "version": "19.6.6", + "resolved": "https://registry.npmjs.org/ngx-extended-pdf-viewer/-/ngx-extended-pdf-viewer-19.6.6.tgz", + "integrity": "sha512-5W84Am1fitaa9Ieij6huSNyPXmqqxRDAO1i5jSF2HcGgvmQTfXMfz3h6ujcYVI3kvDP2yir3YthpKeODTZlUvQ==", + "dependencies": { + "lodash.deburr": "^4.1.0", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0 <18.0.0", + "@angular/core": ">=16.0.0 <18.0.0", + "rxjs": ">=7.0.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/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/node-gyp/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "devOptional": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "dev": true, + "dependencies": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "dev": true, + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pdfjs-dist": { + "version": "2.16.105", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.16.105.tgz", + "integrity": "sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==", + "dependencies": { + "dommatrix": "^1.0.3", + "web-streams-polyfill": "^3.2.1" + }, + "peerDependencies": { + "worker-loader": "^3.0.8" + }, + "peerDependenciesMeta": { + "worker-loader": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/piscina": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.4.0.tgz", + "integrity": "sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==", + "dev": true, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", + "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", + "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protobufjs": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz", + "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/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/read-package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", + "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", + "dev": true + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxfire": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/rxfire/-/rxfire-6.0.5.tgz", + "integrity": "sha512-ycBsANGbya3GNtOBKzZVATLEV+0S9gUrlTfwnN15TCXtgG8OgIMAuv2k9+kMeVaevp/DRp1KT+vYf6Wkop6gvw==", + "peerDependencies": { + "firebase": "^9.0.0 || ^10.0.0", + "rxjs": "^6.0.0 || ^7.0.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-loader": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.1.tgz", + "integrity": "sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==", + "dev": true, + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "dev": true, + "optional": true + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "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/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sigstore": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.2.tgz", + "integrity": "sha512-2A3WvXkQurhuMgORgT60r6pOWiCOO5LlEqY2ADxGBDGVYLSo5HN0uLtb68YpVpuL/Vi8mLTe7+0Dx2Fq8lLqEg==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/sign": "^2.2.3", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "dev": true, + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", + "dev": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "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/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/terser": { + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", + "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "devOptional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tuf-js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", + "integrity": "sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/undici": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.7.1.tgz", + "integrity": "sha512-+Wtb9bAQw6HYWzCnxrPTMVEV3Q1QjYanI0E4q02ehReMuquQdLTEFEYbfs7hcImVYKcQkWSwT6buEmSVIiDDtQ==", + "dev": true, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", + "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", + "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/winston": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", + "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", + "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston/node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "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/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zone.js": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.4.tgz", + "integrity": "sha512-NtTUvIlNELez7Q1DzKVIFZBzNb646boQMgpATo9z3Ftuu/gWvzxCW7jdjcUDoRGxRikrhVHB/zLXh1hxeJawvw==", + "dependencies": { + "tslib": "^2.3.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c28cd25 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "dabubble", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "private": true, + "dependencies": { + "@angular/animations": "^17.2.0", + "@angular/cdk": "^17.3.1", + "@angular/common": "^17.2.0", + "@angular/compiler": "^17.2.0", + "@angular/core": "^17.2.0", + "@angular/fire": "^17.0.1", + "@angular/forms": "^17.2.0", + "@angular/platform-browser": "^17.2.0", + "@angular/platform-browser-dynamic": "^17.2.0", + "@angular/router": "^17.2.0", + "@ctrl/ngx-emoji-mart": "^9.2.0", + "@ngx-translate/core": "^15.0.0", + "@ngx-translate/http-loader": "^8.0.0", + "ng2-pdf-viewer": "^10.0.0", + "ngx-extended-pdf-viewer": "^19.6.6", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.14.3" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^17.2.1", + "@angular/cli": "^17.2.1", + "@angular/compiler-cli": "^17.2.0", + "@types/jasmine": "~5.1.0", + "jasmine-core": "~5.1.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.3.2" + } +} diff --git a/src/app/app.component.html b/src/app/app.component.html new file mode 100644 index 0000000..678b34e --- /dev/null +++ b/src/app/app.component.html @@ -0,0 +1,3 @@ + + + diff --git a/src/app/app.component.scss b/src/app/app.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts new file mode 100644 index 0000000..387cde9 --- /dev/null +++ b/src/app/app.component.spec.ts @@ -0,0 +1,29 @@ +import { TestBed } from '@angular/core/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AppComponent], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have the 'dabubble' title`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app.title).toEqual('dabubble'); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('h1')?.textContent).toContain('Hello, dabubble'); + }); +}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts new file mode 100644 index 0000000..f5bc0b9 --- /dev/null +++ b/src/app/app.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { UserComponent } from './shared/components/user/user.component'; +import { EditUserDetailsComponent } from './shared/components/header/edit-user/edit-user-details/edit-user-details.component'; +import { ToggleBooleanService } from './service/toggle-boolean.service'; +@Component({ + selector: 'app-root', + standalone: true, + imports: [RouterOutlet, UserComponent, EditUserDetailsComponent], + templateUrl: './app.component.html', + styleUrl: './app.component.scss', +}) +export class AppComponent { + title = 'dabubble'; + + constructor(public toggleAllBooleans:ToggleBooleanService){} +} diff --git a/src/app/app.config.ts b/src/app/app.config.ts new file mode 100644 index 0000000..387c40d --- /dev/null +++ b/src/app/app.config.ts @@ -0,0 +1,38 @@ +import { ApplicationConfig, importProvidersFrom } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { HttpClientModule, HttpClient } from '@angular/common/http'; +import { routes } from './app.routes'; +import { initializeApp, provideFirebaseApp } from '@angular/fire/app'; +import { getFirestore, provideFirestore } from '@angular/fire/firestore'; +import { provideStorage, getStorage } from '@angular/fire/storage'; +import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; +import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; +import { TranslateHttpLoader } from '@ngx-translate/http-loader'; +import { firebaseConfig } from './environments/config'; + +export function HttpLoaderFactory(httpClient: HttpClient) { + return new TranslateHttpLoader(httpClient, './assets/i18n/', '.json'); +} + +const translationConfig = { + defaultLanguage: 'de', + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient], + }, +}; + +export const appConfig: ApplicationConfig = { + providers: [ + provideRouter(routes), + importProvidersFrom( + HttpClientModule, + provideFirebaseApp(() => initializeApp(firebaseConfig)), + provideFirestore(() => getFirestore()), + provideStorage(() => getStorage()), + TranslateModule.forRoot(translationConfig) + ), + provideAnimationsAsync(), + ], +}; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts new file mode 100644 index 0000000..0531a2e --- /dev/null +++ b/src/app/app.routes.ts @@ -0,0 +1,22 @@ +import { Routes } from '@angular/router'; +import { MainComponent } from './components/main/main.component'; +import { RegisterComponent } from './components/main-login/register/register.component'; +import { ChooseAvatarComponent } from './components/main-login/choose-avatar/choose-avatar.component'; +import { PasswordForgetComponent } from './components/main-login/password-forget/password-forget.component'; +import { PasswordResetComponent } from './components/main-login/password-reset/password-reset.component'; +import { LoginComponent } from './components/main-login/login/login.component'; +import { ImprintComponent } from './shared/components/imprint/imprint.component'; +import { PrivacyPolicyComponent } from './shared/components/privacy-policy/privacy-policy.component'; + +export const routes: Routes = [ + { path: '', component: MainComponent }, + { path: 'login', component: LoginComponent }, + { path: 'register', component: RegisterComponent }, + { path: 'avatar', component: ChooseAvatarComponent }, + { path: 'passwordForget', component: PasswordForgetComponent }, + { path: 'passwordReset', component: PasswordResetComponent }, + { path: 'main', component: MainComponent }, + { path: 'main/:id', component: MainComponent }, + { path: 'imprint', component: ImprintComponent }, + { path: 'privacy-policy', component: PrivacyPolicyComponent }, +]; diff --git a/src/app/components/main-chat/channel-informations/channel-informations.component.html b/src/app/components/main-chat/channel-informations/channel-informations.component.html new file mode 100644 index 0000000..d8429df --- /dev/null +++ b/src/app/components/main-chat/channel-informations/channel-informations.component.html @@ -0,0 +1,163 @@ + diff --git a/src/app/components/main-chat/channel-informations/channel-informations.component.scss b/src/app/components/main-chat/channel-informations/channel-informations.component.scss new file mode 100644 index 0000000..2896e26 --- /dev/null +++ b/src/app/components/main-chat/channel-informations/channel-informations.component.scss @@ -0,0 +1,317 @@ +@import "./../../../../styles.scss"; + +.menu { + position: absolute; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + z-index: 5; + .whiteBox { + background-color: #fff; + padding: 24px; + width: 460px; + border-top-right-radius: 40px; + border-bottom-left-radius: 40px; + border-bottom-right-radius: 40px; + position: absolute; + top: 188px; + left: 460px; + height: fit-content; + overflow: none; + } +} + +.headerBox { + display: flex; + justify-content: space-between; + width: 100%; +} + +.headline { + display: flex; + align-items: center; + padding: 6px 12px; + max-width: fit-content; + img { + &:first-child { + width: 24px; + height: 25px; + padding-right: 12px; + } + &:nth-child(2) { + width: 14px; + height: 8px; + } + } + p { + font-size: 24px; + font-weight: 700; + padding-right: 12px; + } +} + +.dieableEdit { + color: rgba(0, 0, 0, 0.5) !important; + cursor: context-menu !important; + &:hover { + font-weight: 400 !important; + } +} + +.closeBtn { + display: flex; + justify-content: center; + align-items: center; + width: 37px; + height: 37px; + cursor: pointer; + &:hover { + background-color: #edeefe; + border-radius: 100%; + img { + width: 15px; + height: 15px; + } + } + img { + width: 13px; + height: 13px; + } +} + +.contentChannel { + margin-top: 12px; + padding: 24px; + border-radius: 40px; + border: 1px solid rgba(0, 0, 0, 0.2); + p { + font-size: 18px; + font-weight: 700; + } + .contentHeadline { + display: flex; + justify-content: space-between; + align-items: center; + span { + font-size: 18px; + font-weight: 400; + color: #545af1; + cursor: pointer; + &:hover { + font-weight: 700; + } + } + } +} + +.channelName { + display: flex; + align-items: center; + margin-top: 18px; + img { + width: 16px; + height: 16px; + padding-right: 12px; + } + p { + font-size: 18px; + font-weight: 400; + } + .inputName { + width: 100%; + border: 1px solid #888dec; + outline: none; + height: 12px; + border-radius: 25px; + padding: 8px; + font-size: large; + } + .textareaDescription { + width: 100%; + padding: 16px; + max-height: 104px; + border-radius: 40px; + border: 1px solid #888dec; + resize: none; + font-size: medium; + scrollbar-width: none; + -ms-overflow-style: none; + outline: none; + } +} + +.channelDescription { + display: flex; + align-items: center; + max-height: 200px; + overflow: auto; + padding-top: 18px; + p { + font-size: 18px; + font-weight: 400; + } +} + +.channelCreator { + margin-top: 24px; + .creatorName { + font-size: 24px; + font-weight: 200; + color: #535af1; + } + .warningPTag { + color: rgba(0, 0, 0, 0.5); + font-weight: 300; + font-size: 14px; + } +} + +.line { + margin: 24px 6px; + border: 1px solid rgba(0, 0, 0, 0.2); +} + +.leaveChannel { + display: flex; + justify-content: right; + align-items: center; + margin-top: 18px; +} + +.leaveChannel button { + padding: 12px 25px; + border-radius: 25px; + font-weight: 400; + font-size: 18px; + color: #fff; + border: 0px; + background-color: #444df2; + cursor: pointer; +} + +.leaveChannel button:disabled { + background-color: #999; + cursor: unset; +} + +.leaveChannel button:hover:not(:disabled) { + filter: opacity(70%); +} + +.disableEdit { + width: 18px; + height: auto; + filter: brightness(0) saturate(100%) invert(59%) sepia(0%) saturate(0%) + hue-rotate(156deg) brightness(93%) contrast(84%); +} + +// MEMBERS + +.contentChannelMembers { + margin-top: 12px; + padding: 24px; + border-radius: 40px; + border: 1px solid rgba(0, 0, 0, 0.2); + p { + font-size: 21px; + font-weight: 700; + } + .contentHeadline { + display: flex; + justify-content: space-between; + align-items: center; + } +} + +.allUsers { + max-height: 400px; + overflow: auto; +} + +.user { + display: flex; + align-items: center; + margin: 6px; + padding: 6px; + max-width: fit-content; + cursor: pointer; + .imgBox { + display: flex; + align-items: flex-end; + .userImg { + width: 50px; + height: 50px; + object-fit: cover; + border-radius: 50%; + } + .onlineIcon { + width: 16px; + height: 16px; + border-radius: 50%; + margin-left: -12px; + } + } + p { + font-size: 18px; + font-weight: 400; + padding: 0 12px 0 18px; + text-align: left; + } + &:hover { + background-color: #edeefe; + border-radius: 36px; + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD) { + .menu { + .whiteBox { + top: 188px; + left: 70px; + } + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .header { + height: 36px; + padding: 12px; + } + + .headline { + p { + font-size: 20px; + max-width: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + img { + &:first-child { + width: 18px; + height: 19px; + padding-right: 6px; + } + } + } + + .menu { + background-color: unset; + .whiteBox { + position: fixed; + top: 0px; + bottom: 0; + left: 0; + right: 0; + padding: 12px; + border-radius: 0; + width: calc(100% - 24px); + height: calc(100% - 24px); + overflow: auto; + } + } +} diff --git a/src/app/components/main-chat/channel-informations/channel-informations.component.spec.ts b/src/app/components/main-chat/channel-informations/channel-informations.component.spec.ts new file mode 100644 index 0000000..c46c4ab --- /dev/null +++ b/src/app/components/main-chat/channel-informations/channel-informations.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChannelInformationsComponent } from './channel-informations.component'; + +describe('ChannelInformationsComponent', () => { + let component: ChannelInformationsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ChannelInformationsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ChannelInformationsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/channel-informations/channel-informations.component.ts b/src/app/components/main-chat/channel-informations/channel-informations.component.ts new file mode 100644 index 0000000..32965cc --- /dev/null +++ b/src/app/components/main-chat/channel-informations/channel-informations.component.ts @@ -0,0 +1,236 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { Channel } from '../../../interface/channel.interface'; +import { ChannleService } from '../../../service/channle.service'; +import { UserService } from '../../../service/user.service'; +import { Router } from '@angular/router'; +import { User } from '../../../interface/user.interface'; +import { SharedService } from '../../../service/shared.service'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { OpenSendPrvMessageWindowComponent } from '../show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-channel-informations', + standalone: true, + imports: [ + CommonModule, + FormsModule, + SmallBtnComponent, + OpenSendPrvMessageWindowComponent, + TranslateModule, + ], + templateUrl: './channel-informations.component.html', + styleUrl: './channel-informations.component.scss', +}) +export class ChannelInformationsComponent { + @Input() currentChannel: string = ''; + @Input() viewWidth: number = 0; + @Output() closeEditEmitter: EventEmitter = + new EventEmitter(); + + openEditNameInput: boolean = false; + openEditNameDescription: boolean = false; + nameValue: string = ''; + descriptionValue: string = ''; + getCurrentChannel: Channel[] = []; + openUserWindowBoolean: boolean = false; + user: User[] = []; + + constructor( + private route: Router, + public channelService: ChannleService, + public userService: UserService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD_MOBILE = this.sharedService.RESPONSIVE_THRESHOLD_MOBILE; + + /** + * Closes the menu by emitting a signal to close editing. + */ + showMenu() { + this.closeEditEmitter.emit(true); + } + + /** + * Closes the menu and resets various states. + */ + closeMenu() { + this.closeEditEmitter.emit(false); + this.openEditNameDescription = false; + this.openEditNameInput = false; + this.descriptionValue = ''; + this.nameValue = ''; + this.getCurrentChannel = []; + } + + /** + * Prevents the propagation of an event. + * @param {Event} event - The event to stop propagation. + */ + preventCloseWhiteBox(event: Event) { + event.stopPropagation(); + } + + /** + * Retrieves the channel name based on its ID. + * @param {string} chatId - The ID of the channel. + * @returns {Channel[]} - The filtered channels. + */ + getChannelName(chatId: string) { + const filteredTasks = this.channelService.allChannels.filter( + (channel) => channel.id == chatId + ); + this.getCurrentChannel = filteredTasks; + return filteredTasks; + } + + /** + * Retrieves all channel members based on channel ID. + * @param {string} channelId - The ID of the channel. + * @returns {User[]} - The filtered users. + */ + getAllChannelMembers(channelId: string) { + return this.channelService.allChannels.filter( + (channel) => channel.id === channelId + ); + } + + /** + * Retrieves chat users based on user ID. + * @param {string} userId - The ID of the user. + * @returns {User[]} - The filtered users. + */ + getChatUsers(userId: string) { + return this.userService.allUsers.filter((user) => user.id === userId); + } + + /** + * Retrieves channel members based on channel ID. + * @param {string} chatId - The ID of the channel. + * @returns {User[]} - The filtered users. + */ + getChannelMembers(chatId: string) { + const filteredTasks = this.userService.allUsers.filter( + (user) => user.id == chatId + ); + return filteredTasks; + } + + /** + * Checks if the current user is the creator of the channel. + * @param {string} currentChannel - The ID of the current channel. + * @returns {boolean} - True if the user is the creator, false otherwise. + */ + checkCreator(currentChannel: string) { + const getChannel = this.channelService.allChannels.filter( + (channel) => channel.id == currentChannel + ); + if (getChannel[0].creator === this.userService.getCurrentUserId()) { + return true; + } else { + return false; + } + } + + /** + * Opens a window displaying information about a user. + * @param {User} user - The user to display information about. + */ + openUserWindow(user: User) { + this.user = [user]; + this.openUserWindowBoolean = !this.openUserWindowBoolean; + } + + /** + * Changes the state of the user window. + * @param {boolean} value - The new state of the user window. + */ + changeOpenUserWindowBoolean(value: boolean) { + this.openUserWindowBoolean = value; + } + + /** + * Initiates editing the channel name. + * @param {Event} event - The event that triggered the editing. + */ + editChannelName(event: Event) { + event.stopPropagation(); + this.openEditNameInput = true; + this.nameValue = this.getCurrentChannel[0].name; + } + + /** + * Saves the edited channel name. + * @param {Event} event - The event that triggered the save. + */ + saveEditChannelName(event: Event) { + event.stopPropagation(); + this.openEditNameInput = false; + this.channelService.saveAddedNameOrDescription( + 'channels', + this.currentChannel!, + 'name', + this.nameValue + ); + } + + /** + * Initiates editing the channel description. + * @param {Event} event - The event that triggered the editing. + */ + editChannelDescription(event: Event) { + event.stopPropagation(); + this.openEditNameDescription = true; + this.descriptionValue = this.getCurrentChannel[0].description || ''; + } + + /** + * Saves the edited channel description. + * @param {Event} event - The event that triggered the save. + */ + saveEditChannelDescription(event: Event) { + event.stopPropagation(); + this.openEditNameDescription = false; + this.channelService.saveAddedNameOrDescription( + 'channels', + this.currentChannel!, + 'description', + this.descriptionValue + ); + } + + /** + * Allows the user to leave the channel. + * @param {string} currentChannel - The ID of the current channel. + * @param {Event} event - The event that triggered the action. + */ + leaveChannel(currentChannel: string, event: Event) { + event.stopPropagation(); + const getLogedInUser: string = this.userService.getCurrentUserId(); + const getChannel = this.channelService.allChannels.filter( + (channel) => channel.id == currentChannel + ); + if (getChannel) { + const userIndex = getChannel[0].addedUser.indexOf(getLogedInUser); + if (userIndex !== -1) { + getChannel[0].addedUser.splice(userIndex, 1); + const userArray = getChannel[0].addedUser; + this.channelService.addNewMemberToChannel( + 'channels', + currentChannel, + userArray, + 'leaveChannel' + ); + this.closeEditEmitter.emit(false); + this.route.navigateByUrl(`main`); + } + } + } + + ngOnDestroy() { + this.closeMenu(); + } +} diff --git a/src/app/components/main-chat/chat-content/chat-content.component.html b/src/app/components/main-chat/chat-content/chat-content.component.html new file mode 100644 index 0000000..2335f21 --- /dev/null +++ b/src/app/components/main-chat/chat-content/chat-content.component.html @@ -0,0 +1,39 @@ +
+ @if (!hideContentWindow) { +
+ + @for (chat of getChatChannel(currentChannel); track chat; let i = $index) { + @for (user of getChatUsers(chat.userId); track user) { + @if(!isPublishedToday(chat.publishedTimestamp)) { +
+ +

{{ convertTimestampDate(chat.publishedTimestamp) }}

+ +
+ } +
+ +
+ } } +
+ } + +
diff --git a/src/app/components/main-chat/chat-content/chat-content.component.scss b/src/app/components/main-chat/chat-content/chat-content.component.scss new file mode 100644 index 0000000..7c08158 --- /dev/null +++ b/src/app/components/main-chat/chat-content/chat-content.component.scss @@ -0,0 +1,73 @@ +@import "../../../../styles.scss"; + +section { + display: flex; + flex-direction: column; + justify-content: end; + height: calc(100vh - 210px); + position: relative; +} + +.privatChatHeight { + height: calc(100vh - 230px); +} + +.searchChatHeight { + margin-top: 64px; + height: calc(100vh - 274px); +} + +.mirror { + transform: scaleX(-1); +} + +.content { + overflow-y: auto; +} + +.line { + display: flex; + justify-content: space-between; + align-items: center; + margin: 26px 0; + .lines { + width: 100%; + height: 1px; + background-color: #adb0d9; + } + p { + text-align: center; + white-space: nowrap; + font-size: 18px; + font-weight: 400; + border: 1px solid #adb0d9; + padding: 6px 12px; + border-radius: 24px; + } +} + +//----------- responsive --------------- + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + section { + height: calc(100vh - 144px); + } + + .privatChatHeight { + height: calc(100vh - 158px); + } + + .searchChatHeight { + margin-top: 88px; + height: calc(100vh - 188px); + } +} + +@media screen and (max-width: 380px) { + section { + height: calc(100vh - 144px); + } + .privatChatHeight { + height: calc(100vh - 158px); + } +} diff --git a/src/app/components/main-chat/chat-content/chat-content.component.spec.ts b/src/app/components/main-chat/chat-content/chat-content.component.spec.ts new file mode 100644 index 0000000..6168e68 --- /dev/null +++ b/src/app/components/main-chat/chat-content/chat-content.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChatContentComponent } from './chat-content.component'; + +describe('ChatContentComponent', () => { + let component: ChatContentComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ChatContentComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ChatContentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/chat-content/chat-content.component.ts b/src/app/components/main-chat/chat-content/chat-content.component.ts new file mode 100644 index 0000000..80d2488 --- /dev/null +++ b/src/app/components/main-chat/chat-content/chat-content.component.ts @@ -0,0 +1,179 @@ +import { + AfterViewChecked, + AfterViewInit, + Component, + ElementRef, + Input, + Renderer2, + ViewChild, +} from '@angular/core'; +import { MainChatComponent } from '../main-chat.component'; +import { ChatService } from '../../../service/chat.service'; +import { UserService } from '../../../service/user.service'; +import { SingleChatComponent } from '../single-chat/single-chat.component'; +import { ChatMsgBoxComponent } from '../chat-msg-box/chat-msg-box.component'; +import { CommonModule } from '@angular/common'; +import { DownloadFilesService } from '../../../service/download-files.service'; +import { ChannleService } from '../../../service/channle.service'; +import { InfoComponent } from '../info/info.component'; + +@Component({ + selector: 'app-chat-content', + standalone: true, + imports: [ + MainChatComponent, + SingleChatComponent, + ChatMsgBoxComponent, + CommonModule, + InfoComponent, + ], + templateUrl: './chat-content.component.html', + styleUrl: './chat-content.component.scss', +}) +export class ChatContentComponent implements AfterViewInit, AfterViewChecked { + @Input() currentChannel: string = ''; + @Input() isPrivatChannel: boolean = false; + @Input() isSearchChannel: boolean = false; + @Input() hideContentWindow: boolean = false; + @Input() viewWidth: number = 0; + @Input() getChatChannel!: (currentChannel: string) => any; + @Input() getChatUsers!: (currentChannel: string) => any; + @ViewChild('messageBody') messageBody: ElementRef | undefined; + filesLoaded: boolean = false; + isNewMessage: boolean = false; + + constructor( + private chatService: ChatService, + private userService: UserService, + public channelService: ChannleService, + private downloadFilesService: DownloadFilesService, + private renderer: Renderer2 + ) {} + + ngAfterViewInit() { + this.scrollToBottom(); + this.checkIfLoadedFirebaseFiles(); + } + + ngAfterViewChecked() { + if (this.filesLoaded) { + this.scrollToBottom(); + this.filesLoaded = false; + } + } + + /** + * Updates the state of isNewMessage and optionally scrolls to the bottom. + * @param {boolean} variable - The new value for isNewMessage. + */ + editMsgEmitter(variable: boolean) { + this.isNewMessage = variable; + if (this.isNewMessage) { + this.scrollToBottom(); + } + } + + /** + * Checks whether Firebase files have been loaded from the server + */ + checkIfLoadedFirebaseFiles() { + this.downloadFilesService.downloadedFiles.subscribe((files) => { + if (files.length > 0) { + this.filesLoaded = true; + } + }); + } + + /** + * Scrolls to the bottom of the message body element. + */ + scrollToBottom(): void { + if (this.messageBody) { + const element = this.messageBody.nativeElement; + this.renderer.setProperty( + element, + 'scrollTop', + element.scrollHeight - element.clientHeight + ); + } + } + + /** + * Checks whether multiple chats have been posted for the date + * @param {number} timestamp - The timestamp to be checked. + * @returns {boolean} - Returns true or false. + */ + isPublishedToday(timestamp: number) { + return this.getAllChatsOnTheDate(this.currentChannel, timestamp).includes( + timestamp + ); + } + + /** + * Retrieves timestamps of all chats posted on a specific date in a given channel. + * @param {string} currentChannel - The current channel ID. + * @param {number} timestamp - The timestamp representing the date. + * @returns {number[]} An array of timestamps of messages. + */ + getAllChatsOnTheDate(currentChannel: string, timestamp: number) { + const todayDate = new Date(timestamp * 1000); + const todayTimestamps = this.chatService.allChats + .filter((chat) => chat.channelId === currentChannel) + .filter((chat) => { + const chatDate = new Date(chat.publishedTimestamp * 1000); + return ( + chatDate.getFullYear() === todayDate.getFullYear() && + chatDate.getMonth() === todayDate.getMonth() && + chatDate.getDate() === todayDate.getDate() + ); + }) + .map((chat) => chat.publishedTimestamp); + + todayTimestamps.shift(); + return todayTimestamps; + } + + /** + * Converts a timestamp to a formatted date string. + * @param {number} timestamp - The timestamp to convert. + * @returns {string} The formatted date string. + */ + convertTimestampDate(timestamp: number) { + const currentDate = new Date(); + const inputDate = new Date(timestamp * 1000); + + const days = [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ]; + const months = [ + 'Jan.', + 'Feb.', + 'Mar.', + 'Apr.', + 'May.', + 'Jun.', + 'Jul.', + 'Aug.', + 'Sep.', + 'Oct.', + 'Nov.', + 'Dec.', + ]; + + const dayNumber = inputDate.getDate(); + const day = days[inputDate.getDay()]; + const month = months[inputDate.getMonth()]; + + if (inputDate.toDateString() === currentDate.toDateString()) { + return `Today`; + } else { + return `${day}, ${dayNumber} ${month}`; + } + } +} diff --git a/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.html b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.html new file mode 100644 index 0000000..e87d820 --- /dev/null +++ b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.html @@ -0,0 +1,132 @@ +
+
+ @if(hasFile){ +
+ + +
+ } + +
+ +
+
+ + + + @if (target == 'chats') { + +
+ @if (toggleBoolean.selectUserInMsgBox) { +
+ @for(user of userService.getFiltertUsers; track user){ +
+
+ + +
+

{{ user.firstName }} {{ user.lastName }}

+
+ } +
+ } +
+ } @if(downloadFilesService.uploadFiles.length >= 1){ +

+ {{ "channel-msg-box.text" | translate }} +

+ } +
+ @if(textArea == ''){ + + } @else { + + } + + @if (openSmallWindow) { +
+ @if (showChannels) { @for (i of checkIfUserHasAccessToChannel(); track + $index) { +

{{ i.name }}

+ } }@else if (showUsers) { @for (i of userService.allUsers; track $index) { +
+
+ + +
+

{{ i.firstName }} {{ i.lastName }}

+
+ } } +
+ } +
+ @if (isEmojiPickerVisible) { + + } +
diff --git a/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.scss b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.scss new file mode 100644 index 0000000..3a4c8fa --- /dev/null +++ b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.scss @@ -0,0 +1,241 @@ +@import "../../../../styles.scss"; + +section { + width: auto; + margin: 24px; + padding: 24px; + padding-bottom: 54px; + height: 95px; + border-radius: 40px; + border: 1px solid rgba(0, 0, 0, 0.2); + margin-top: 12px; + background-color: #fff; + position: relative; + > textarea { + width: 100%; + height: 100%; + cursor: pointer; + border: none; + outline: none; + resize: none; + font-family: "Nunito"; + font-size: large; + input { + position: absolute; + top: 0; + left: 0; + background-color: rgb(236, 236, 236); + width: 10px; + height: 10px; + } + } + .positionAllIcons { + @include displayFlex($j: space-between); + .positionSpecialIcons { + @include displayFlex($j: space-between, $g: 3px); + } + } + .sendIcon { + padding: 6px; + cursor: pointer; + transform: 0.3 ease-in-out; + &:hover { + scale: 1.1; + filter: brightness(0) saturate(100%) invert(56%) sepia(97%) + saturate(1270%) hue-rotate(204deg) brightness(95%) contrast(94%); + } + } +} + +.sendIconDisabled{ + padding: 6px; + transform: 0.3 ease-in-out; + filter: brightness(0) saturate(100%) invert(78%) sepia(4%) saturate(4098%) hue-rotate(207deg) brightness(99%) contrast(98%); +} + +.verticalLine { + height: 28px; + padding: 6px; +} + +app-small-btn { + padding: 6px 3px; +} + +.fileBox { + border: 1px solid #e5e5e5; + border-radius: 10px; + padding: 5px 10px; + background-color: #eee; + max-width: 40px; + max-height: 20px; + margin-right: 12px; + position: relative; + @include displayFlex(); + .fileIcons { + margin-left: 12px; + margin-right: 12px; + cursor: pointer; + } +} + +app-emoji-picker { + position: absolute; + bottom: 50px; + left: 80px; + z-index: 3; +} + +.posiotionDataFromPc { + margin-top: -40px; + display: flex; + width: 60px; +} + +.closeIcon { + position: absolute; + top: -4px; + right: -4px; + width: 12px; + object-fit: contain; + cursor: pointer; + transition: 0.3s ease-in-out; + &:hover { + background-color: red; + border-radius: 50%; + } +} + +.smileysBackground { + position: absolute; + left: 0; + top: 0; + width: 100vw; + height: 100vh; +} + +.showWanrningNotice { + animation: shwoWN 0.3s ease-in-out; +} + +@keyframes shwoWN { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.positionOfAllUsersInBox { + position: absolute; + bottom: 36px; + @include displayFlex($j: flex-start, $a: flex-start); + flex-direction: column; + height: 210px; + overflow: auto; + width: 240px; + background-color: #fff; + border: 1px solid #745dda; + border-radius: 25px; + border-bottom-left-radius: 0; + scrollbar-width: none; + -ms-overflow-style: none; + padding: 8px; + .user { + @include displayFlex($g: 12px); + padding: 6px; + cursor: pointer; + transition: 0.2s ease-in-out; + + &:hover { + background-color: #edeefe; + border-radius: 25px; + } + + .positionImgs { + @include displayFlex($a: flex-end); + + .avatarImg { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 50%; + } + + .onlineIcon { + width: 12px; + height: 12px; + margin-left: -10px; + } + } + } +} + +.addUserBox { + display: flex; +} + +.warningMessage{ + color: red; +} + +.filteredElementWindow2 { + z-index: 1; + max-height: 240px; + overflow: auto; + scrollbar-width: none; + position: absolute; + bottom: 100%; + left: 100px; + border-radius: 25px; + border-bottom-left-radius: 0; + border: 1px solid #888dec; + background-color: #ffffff; + padding: 8px; + box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, + rgba(0, 0, 0, 0.3) 0px 8px 16px -8px; + display: flex; + align-items: flex-start; + flex-direction: column; + .user2 { + @include displayFlex($j: flex-start); + padding: 6px; + margin-bottom: 6px; + cursor: pointer; + transition: 0.2s ease-in-out; + &:hover { + background-color: #edeefe; + border-radius: 25px; + } + .positionImgs2 { + @include displayFlex($a: flex-end); + .avatarImg2 { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 50%; + } + .onlineIconFilterWindow { + height: 12px; + width: 12px; + margin-left: -10px; + margin-right: 8px; + } + } + } +} + +//----------- responsive --------------- + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + section { + height: 50px; + padding-bottom: 54px; + margin: 12px; + } + + .warningMessage{ + font-size: 12px; + } +} diff --git a/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.spec.ts b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.spec.ts new file mode 100644 index 0000000..5806df7 --- /dev/null +++ b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChatMsgBoxComponent } from './chat-msg-box.component'; + +describe('ChatMsgBoxComponent', () => { + let component: ChatMsgBoxComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ChatMsgBoxComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ChatMsgBoxComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.ts b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.ts new file mode 100644 index 0000000..cf55b05 --- /dev/null +++ b/src/app/components/main-chat/chat-msg-box/chat-msg-box.component.ts @@ -0,0 +1,358 @@ +import { CommonModule } from '@angular/common'; +import { + Component, + ElementRef, + EventEmitter, + Input, + Output, + ViewChild, +} from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { PickerComponent } from '@ctrl/ngx-emoji-mart'; +import { Firestore, addDoc, collection } from '@angular/fire/firestore'; +import { DownloadFilesService } from '../../../service/download-files.service'; +import { UserService } from '../../../service/user.service'; +import { EmojiPickerComponent } from '../../../shared/components/emoji-picker/emoji-picker.component'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { ChatService } from '../../../service/chat.service'; +import { Router } from '@angular/router'; +import { ChannleService } from '../../../service/channle.service'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; +import { User } from '../../../interface/user.interface'; +import { MessageData } from '../../../interface/chat.interface'; +import { TranslateModule } from '@ngx-translate/core'; +import { Channel } from '../../../interface/channel.interface'; + +@Component({ + selector: 'app-chat-msg-box', + standalone: true, + imports: [ + CommonModule, + FormsModule, + PickerComponent, + EmojiPickerComponent, + SmallBtnComponent, + TranslateModule, + ], + templateUrl: './chat-msg-box.component.html', + styleUrl: './chat-msg-box.component.scss', +}) +export class ChatMsgBoxComponent { + @Input() currentChannel: string = ''; + @Input() target: string = ''; + @Output() newMsgEmitter: EventEmitter = new EventEmitter(); + @ViewChild('textarea') textAreaRef!: ElementRef; + + hasFile: boolean = false; + currentFiles!: FileList; + files: any; + getFileIcons = [ + './assets/img/documentIcon.svg', + './assets/img/imgIcon.svg', + './assets/img/mp3Icon.svg', + './assets/img/pdfIcon.svg', + './assets/img/videoIcon.svg', + ]; + textArea: string = ''; + isEmojiPickerVisible: boolean | undefined; + currentChatValue: string = ''; + showTargetMember: boolean = true; + showChannels: boolean = false; + showUsers: boolean = false; + openSmallWindow: boolean = false; + + constructor( + private route: Router, + public downloadFilesService: DownloadFilesService, + private firestore: Firestore, + public userService: UserService, + private chatService: ChatService, + public channelService: ChannleService, + public toggleBoolean: ToggleBooleanService + ) {} + + /** + * Handles the output from the emoji picker. + * @param $event The selected emoji. + */ + emojiOutputEmitter($event: any) { + this.addEmoji($event); + } + + /** + * Select Textarea at onload. + */ + ngAfterViewInit() { + this.textAreaRef.nativeElement.select(); + } + + /** + * Handles file input change event. + * @param event The file change event. + */ + onFileChange(event: any) { + if (this.downloadFilesService.uploadFiles.length < 1) { + this.currentFiles = event.target.files; + this.hasFile = this.currentFiles!.length > 0; + if (this.currentFiles) { + for (let i = 0; i < this.currentFiles.length; i++) { + const fileInfo = this.currentFiles[i]; + this.downloadFilesService.uploadFiles.push(fileInfo); + } + } + } + } + + /** + * Checks the file type and returns the corresponding icon. + * @param fileInfo The file object. + * @returns The file icon path. + */ + checkIcon(fileInfo: any) { + if (fileInfo.type == 'audio/mpeg') { + return this.getFileIcons[2]; + } else if (fileInfo.type == 'image/jpeg') { + return this.getFileIcons[1]; + } else if (fileInfo.type == 'application/pdf') { + return this.getFileIcons[3]; + } else if (fileInfo.type == 'video/mp4') { + return this.getFileIcons[4]; + } else { + return this.getFileIcons[0]; + } + } + + /** + * Deletes the selected file. + * @param file The file to be deleted. + */ + deleteFile(file: File) { + const index = this.downloadFilesService.uploadFiles.indexOf(file); + if (index !== -1) { + this.downloadFilesService.uploadFiles.splice(index, 1); + this.hasFile = this.downloadFilesService.uploadFiles.length > 0; + } + } + + /** + * Opens the selected file in a new tab. + * @param file The file to be opened. + */ + showCurrentFile(file: File) { + const blob = new Blob([file], { type: file.type }); + const url = URL.createObjectURL(blob); + window.open(url, '_blank'); + } + + /** + * Adds the selected emoji to the message text area. + * @param event The selected emoji. + */ + public addEmoji(event: any) { + this.textArea = `${this.textArea}${event}`; + this.isEmojiPickerVisible = false; + } + + /** + * Toggles the visibility of the emoji picker. + */ + toggleEmojiPicker() { + this.isEmojiPickerVisible = !this.isEmojiPickerVisible; + } + + /** + * Displays the list of target chat users. + * @param event The event object. + */ + targetChatUser(event: Event) { + event.stopPropagation(); + this.toggleBoolean.selectUserInMsgBox = true; + } + + /** + * Appends the selected user's name to the message text area. + * @param user The selected user. + */ + chooseUser(user: User) { + const userName = ` @${user.firstName} ${user.lastName} `; + + this.textArea += userName; + this.toggleBoolean.selectUserInMsgBox = false; + } + + /** + * Sends a message when Enter key is pressed. + * @param e The keyboard event. + */ + sendMessageWithEnter(e: KeyboardEvent) { + if (this.textArea.trim() !== '') { + if (e.keyCode === 13) { + this.sendMessage(); + } + } + } + + /** + * Sends the message to the target channel. + */ + async sendMessage() { + if (this.currentChannel && this.textArea.trim() !== '') { + const messageRef = collection(this.firestore, this.target); + const messageData = this.checkCollection(this.target); + if (messageData) { + await addDoc(messageRef, messageData) + .then((docRef) => { + this.downloadFilesService.loadAllFiles(docRef.id); + }) + .catch((error) => { + console.error('Error adding document: ', error); + }); + } else { + console.error('Invalid target:', this.target); + } + } + this.forwardToChannel(); + this.resetValues(); + this.newMsgEmitter.emit(true); + } + + /** + * Checks the target collection and returns the message data. + * @param target The target collection. + * @returns The message data. + */ + checkCollection(target: string): MessageData | null { + let messageData: Partial = { + message: this.textArea, + publishedTimestamp: Math.floor(Date.now() / 1000), + userId: this.userService.getCurrentUserId(), + edited: false, + }; + + if (target === 'chats') { + messageData.channelId = this.checkChannelId(); + } else if (target === 'chat-answers') { + messageData.chatId = this.checkChatId(); + } else { + console.error('Invalid target:', target); + return null; + } + return messageData as MessageData; + } + + /** + * Checks + * the channel ID based on the chat service. + * @returns The channel ID. + */ + checkChannelId() { + if (this.chatService.getChannelId) { + return this.chatService.getChannelId; + } else if (this.chatService.getPrvChatId) { + return this.chatService.getPrvChatId; + } else if ( + this.currentChannel === 'searchBar' && + this.chatService.inputValue === '' + ) { + return ''; + } + return this.currentChannel; + } + + /** + * Checks the chat ID based on the chat service. + * @returns The chat ID. + */ + checkChatId() { + if (this.chatService.isSecondaryChatId) { + return this.chatService.isSecondaryChatId; + } + return; + } + + /** + * Navigates to the target channel after sending the message. + */ + forwardToChannel() { + if (this.chatService.getChannelId || this.chatService.getPrvChatId) { + this.route.navigateByUrl(`/main/${this.checkChannelId()}`); + } + } + + /** + * Close popups by leaving with the mouse the chat-msg-box. + */ + mouseLeave() { + this.isEmojiPickerVisible = false; + this.toggleBoolean.selectUserInMsgBox = false; + this.openSmallWindow = false; + this.showChannels = false; + this.showUsers = false; + } + + /** + * Open channels or user window by pressing @ or #. + */ + checkChannelAndUser(e: KeyboardEvent) { + if (e.key === '#') { + this.openSmallWindow = true; + this.showChannels = true; + this.showUsers = false; + } else if (e.key === '@') { + this.openSmallWindow = true; + this.showChannels = false; + this.showUsers = true; + } + if (e.key === 'Backspace') { + this.openSmallWindow = false; + this.showChannels = false; + this.showUsers = false; + } + } + + /** + * Checks if the current user has access to any channels. + * @returns {Channel[]} Array of Channel objects that the user has access to. + */ + checkIfUserHasAccessToChannel() { + const isUserAChannelMember = this.channelService.allChannels.some( + (channel) => + channel.addedUser.includes(this.userService.getCurrentUserId()) + ); + + if (isUserAChannelMember) { + return this.channelService.allChannels.filter((channel) => + channel.addedUser.includes(this.userService.getCurrentUserId()) + ); + } + return []; + } + + /** + * Chooses an element and performs necessary actions based on its type. + * @param {Channel | User} element - The element to choose. + */ + chooseElement(element: Channel | User) { + if ('firstName' in element) { + this.textArea += `${element.firstName} ${element.lastName} `; + } else { + this.textArea += `${element.name} `; + } + this.showUsers = false; + this.showChannels = false; + this.openSmallWindow = false; + this.textAreaRef.nativeElement.focus(); + } + + /** + * Resets input values after sending the message. + */ + resetValues() { + this.textArea = ''; + this.downloadFilesService.uploadFiles = []; + this.hasFile = false; + this.chatService.inputValue = ''; + this.chatService.getChannelId = ''; + this.chatService.getPrvChatId = ''; + } +} diff --git a/src/app/components/main-chat/info/info.component.html b/src/app/components/main-chat/info/info.component.html new file mode 100644 index 0000000..c2ffbb2 --- /dev/null +++ b/src/app/components/main-chat/info/info.component.html @@ -0,0 +1,75 @@ +
+ + @if (getChannel(currentChannel).length > 0) { +
# {{ getChannel(currentChannel)[0].name }}
+

+ {{ "info.channelCreate" | translate }} + @if(getChannel(currentChannel)[0].creator == "Admin") { Admin } @else { @for + (user of getChatUsers(getChannel(currentChannel)[0].creator); track user) { + {{ user.firstName }} + {{ user.lastName }} + } } {{ "info.channelCreate2" | translate }} + {{ timeConverter(getChannel(currentChannel)[0].createdDate) + }}{{ "info.channelCreate3" | translate }} + #{{ getChannel(currentChannel)[0].name }}. +

+ + } @if (getPrivatChannel(currentChannel).length > 0) { + + @if (getPrivatChannel(currentChannel)[0].talkToUserId == + userService.getCurrentUserId() && + getPrivatChannel(currentChannel)[0].creatorId == + userService.getCurrentUserId()) { +
+ @for (user of getChatUsers(getPrivatChannel(currentChannel)[0].creatorId); + track user) { +
+ +
+

{{ user.firstName }} {{ user.lastName }} (Du)

+ } +
+

+ {{ "info.notice" | translate }} +

+ } @else { + + @if (getPrivatChannel(currentChannel)[0].talkToUserId == + userService.getCurrentUserId()) { +
+ @for (user of getChatUsers(getPrivatChannel(currentChannel)[0].creatorId); + track user) { +
+ +
+

{{ user.firstName }} {{ user.lastName }}

+ } +
+

+ {{ "info.talkTo" | translate }} @for (user of + getChatUsers(getPrivatChannel(currentChannel)[0].creatorId); track user) { + @{{ user.firstName }}{{ user.lastName }} + } {{ "info.talkTo2" | translate }} +

+ } @else { + +
+ @for (user of + getChatUsers(getPrivatChannel(currentChannel)[0].talkToUserId); track user) + { +
+ +
+

{{ user.firstName }} {{ user.lastName }}

+ } +
+

+ {{ "info.talkTo" | translate }} @for (user of + getChatUsers(getPrivatChannel(currentChannel)[0].talkToUserId); track user) + { + @{{ user.firstName }} {{ user.lastName }} + } {{ "info.talkTo2" | translate }} +

+ } } } +
diff --git a/src/app/components/main-chat/info/info.component.scss b/src/app/components/main-chat/info/info.component.scss new file mode 100644 index 0000000..f1b9e37 --- /dev/null +++ b/src/app/components/main-chat/info/info.component.scss @@ -0,0 +1,70 @@ +@import "../../../../styles.scss"; + +section { + padding: 32px 48px; +} + +.headline { + font-size: 24px; + font-weight: 700; + padding-bottom: 12px; +} + +p { + font-size: 20px; + font-weight: 400; +} + +span { + color: #535af1; +} + +.headlinePrvChat { + display: flex; + align-items: center; + padding-bottom: 12px; + max-width: fit-content; + .imgBoxPrvChat { + display: flex; + margin-right: 16px; + .imgUserPrvChat { + width: 56px; + height: 56px; + object-fit: cover; + border-radius: 50%; + } + } + p { + font-size: 24px; + font-weight: 700; + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + section { + padding: 12px; + } + + .headline { + font-size: 20px; + } + + p { + font-size: 18px; + } + + .headlinePrvChat { + .imgBoxPrvChat { + margin-right: 12px; + .imgUserPrvChat { + width: 50px; + height: 50px; + } + } + p { + font-size: 20px; + } + } +} diff --git a/src/app/components/main-chat/info/info.component.spec.ts b/src/app/components/main-chat/info/info.component.spec.ts new file mode 100644 index 0000000..2064c5e --- /dev/null +++ b/src/app/components/main-chat/info/info.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { InfoComponent } from './info.component'; + +describe('InfoComponent', () => { + let component: InfoComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [InfoComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(InfoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/info/info.component.ts b/src/app/components/main-chat/info/info.component.ts new file mode 100644 index 0000000..cfa1ddf --- /dev/null +++ b/src/app/components/main-chat/info/info.component.ts @@ -0,0 +1,84 @@ +import { Component, Input } from '@angular/core'; +import { ChannleService } from '../../../service/channle.service'; +import { UserService } from '../../../service/user.service'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-info', + standalone: true, + imports: [TranslateModule], + templateUrl: './info.component.html', + styleUrl: './info.component.scss', +}) +export class InfoComponent { + @Input() currentChannel: string = ''; + + constructor( + private channelService: ChannleService, + public userService: UserService + ) {} + + /** + * Retrieves chat users based on the provided chat ID. + * @param {string} chatId - The ID of the chat. + * @returns {Array} - An array containing the users associated with the chat. + */ + getChatUsers(chatId: string) { + const filteredTasks = this.userService.allUsers.filter( + (user) => user.id == chatId + ); + return filteredTasks; + } + + /** + * Retrieves a channel based on the provided chat ID. + * @param {string} chatId - The ID of the chat. + * @returns {Array} - An array containing the channel matching the provided chat ID. + */ + getChannel(chatId: string) { + const filteredTasks = this.channelService.allChannels.filter( + (channel) => channel.id == chatId + ); + return filteredTasks; + } + + /** + * Retrieves a private channel based on the provided chat ID. + * @param {string} chatId - The ID of the chat. + * @returns {Array} - An array containing the private channel matching the provided chat ID. + */ + getPrivatChannel(chatId: string) { + const filteredTasks = this.channelService.allPrvChannels.filter( + (channel) => channel.id == chatId + ); + return filteredTasks; + } + + /** + * Converts a date string to a formatted time string. + * @param {string} dateString - The date string to convert. + * @returns {string} - The formatted time string (e.g., "Jan. 1, 2022"). + */ + timeConverter(dateString: string) { + var a = new Date(dateString); + var months = [ + 'Jan.', + 'Feb.', + 'Mar.', + 'Apr.', + 'May.', + 'Jun.', + 'Jul.', + 'Aug.', + 'Sep.', + 'Oct.', + 'Nov.', + 'Dec.', + ]; + var year = a.getFullYear(); + var month = months[a.getMonth()]; + var date = a.getDate(); + var time = month + ' ' + date + ', ' + year; + return time; + } +} diff --git a/src/app/components/main-chat/main-chat.component.html b/src/app/components/main-chat/main-chat.component.html new file mode 100644 index 0000000..5c5e913 --- /dev/null +++ b/src/app/components/main-chat/main-chat.component.html @@ -0,0 +1,179 @@ +
+ @if (checkCurrentChannel(currentChannel) == 'searchBar') { + +
+

{{ "main-chat.message" | translate }}

+ + @if (toggleBoolean.openSearchWindow) { + +
+ @if (firstLetter == '#') { + + @for (i of checkIfUserHasAccessToChannel(); track $index) { +

+ } } @else if (firstLetter == '@') { + + @for (i of userService.allUsers; track $index) { +
+
+ + +
+

+
+ } } +
+ } +
+
+ + +
+ } @else { @if(checkCurrentChannel(currentChannel) == 'allPrvChannels'){ + + @for (user of getPrvChat(currentChannel); track user; let i = $index) { +
+
+ @if (user.talkToUserId == userService.getCurrentUserId()) { +
+ + +
+

+ {{ filterUser(user.creatorId)[i].firstName }} + {{ filterUser(user.creatorId)[i].lastName }} +

+ } @else { +
+ +
+

+ {{ filterUser(user.talkToUserId)[i].firstName }} + {{ filterUser(user.talkToUserId)[i].lastName }} +

+ } +
+
+ + + } } @else if (checkCurrentChannel(currentChannel) == 'allChannels') { + + @for(channel of getChannelName(currentChannel); track channel) { +
+
+ +

{{ channel.name }}

+ +
+
+ @if (filterChannelForSelectedUser(currentChannel)) { +
+ @for(user of userService.getFiltertUsers.slice(0, 3) ; track user) { +
+ +
+ } +
+ +
+

{{ userService.getFiltertUsers.length }}

+
+ + } +
+
+ + + + } + + @if (openMenu) { + + } } } @if (showProfil) { + + } +
diff --git a/src/app/components/main-chat/main-chat.component.scss b/src/app/components/main-chat/main-chat.component.scss new file mode 100644 index 0000000..5fa86a7 --- /dev/null +++ b/src/app/components/main-chat/main-chat.component.scss @@ -0,0 +1,296 @@ +@import "./../../../styles.scss"; + +section { + height: 100%; + border-radius: 24px; + background-color: #fff; +} + +.header { + height: 40px; + padding: 24px 48px; + box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.05); + @include displayFlex($j: space-between); +} + +.headline { + display: flex; + align-items: center; + padding: 6px 12px; + max-width: fit-content; + cursor: pointer; + img { + &:first-child { + width: 24px; + height: 25px; + padding-right: 12px; + } + &:nth-child(2) { + width: 14px; + height: 8px; + } + } + p { + font-size: 24px; + font-weight: 700; + padding-right: 12px; + } + &:hover { + background-color: #edeefe; + border-radius: 24px; + } +} + +.addUserToChannelBox { + @include displayFlex($g: 12px); + .addedUsers { + @include displayFlex($g: 8px); + width: auto; + height: 40px; + padding: 3px; + padding-left: 26px; + border-radius: 25px; + cursor: pointer; + transition: background-color 0.2s ease-in-out; + &:hover { + background-color: #edeefe; + } + .userAvatar { + width: 40px; + height: 40px; + object-fit: cover; + background-color: whitesmoke; + border-radius: 50%; + @include displayFlex(); + margin-left: -22px; + img { + width: 36px; + height: 36px; + object-fit: cover; + border-radius: 50%; + } + } + h3 { + padding-right: 8px; + } + } +} + +// -------- prv chat-------- + +.headerPrvChat { + height: 60px; + padding: 24px 48px; + box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.05); + @include displayFlex($j: space-between); +} + +.headerBoxPrvChat { + display: flex; + justify-content: space-between; + width: 100%; +} + +.headlinePrvChat { + display: flex; + align-items: center; + padding: 6px 12px; + max-width: fit-content; + cursor: pointer; + .imgBoxPrvChat { + @include displayFlex($a: flex-end); + margin-right: 16px; + .imgUserPrvChat { + width: 56px; + height: 56px; + object-fit: cover; + border-radius: 50%; + } + .onlineIcon { + width: 16px; + height: 16px; + border-radius: 50%; + margin-left: -12px; + } + } + p { + font-size: 24px; + font-weight: 700; + padding-right: 12px; + } + &:hover { + background-color: #edeefe; + border-radius: 35px; + } +} + +.headerSearchBar { + height: auto; + border-top-left-radius: 25px; + border-top-right-radius: 25px; + box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.05); + @include displayFlex($a: flex-start); + flex-direction: column; + padding: 24px 48px; + position: relative; + p { + font-size: 24px; + font-weight: 700; + } + input { + width: calc(100% - 8px); + height: 55px; + border-radius: 26px; + padding-left: 24px; + margin-top: 12px; + font-size: 18px; + font-weight: 400; + border: 1px solid #888dec; + font-family: "Nunito", sans-serif; + outline: none; + &:hover { + border: 1px solid #5f66e7; + } + } +} + +.filteredElementWindow { + z-index: 1; + max-height: 240px; + overflow: auto; + scrollbar-width: none; + position: absolute; + top: 127px; + left: 80px; + border-radius: 25px; + border-top-left-radius: 0; + border: 1px solid #888dec; + background-color: #ffffff; + padding: 8px; + box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, + rgba(0, 0, 0, 0.3) 0px 8px 16px -8px; + display: flex; + align-items: flex-start; + flex-direction: column; + .user { + @include displayFlex($j: flex-start); + padding: 6px; + margin-bottom: 6px; + cursor: pointer; + transition: 0.2s ease-in-out; + &:hover { + background-color: #edeefe; + border-radius: 25px; + } + .positionImgs { + @include displayFlex($a: flex-end); + .avatarImg { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 50%; + } + .onlineIconFilterWindow { + height: 12px; + width: 12px; + margin-left: -10px; + margin-right: 8px; + } + } + } +} + +.dotsImg { + @include displayFlex($a: flex-end); + margin-bottom: -26px; + margin-left: -10px; + img { + width: 6px; + height: 6px; + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + section { + border-radius: 0; + } + + .addUserToChannelBox { + .addedUsers { + display: none; + } + } + + .header { + height: 36px; + padding: 12px; + } + + .headerPrvChat { + height: 54px; + padding: 12px; + } + + .headline { + p { + font-size: 20px; + max-width: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + img { + &:first-child { + width: 18px; + height: 19px; + padding-right: 6px; + } + } + } + + .headerSearchBar { + height: 84px; + padding: 12px; + p { + font-size: 20px; + } + input { + width: calc(100% - 28px); + height: 50px; + } + } + + .headlinePrvChat { + .imgBoxPrvChat { + margin-right: 16px; + .imgUserPrvChat { + width: 50px; + height: 50px; + } + .onlineIcon { + width: 12px; + height: 12px; + border-radius: 50%; + margin-left: -12px; + } + } + p { + font-size: 20px; + } + &:hover { + background-color: #edeefe; + border-radius: 35px; + } + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .filteredElementWindow { + top: 95px; + left: 45px; + } +} diff --git a/src/app/components/main-chat/main-chat.component.spec.ts b/src/app/components/main-chat/main-chat.component.spec.ts new file mode 100644 index 0000000..d5fce28 --- /dev/null +++ b/src/app/components/main-chat/main-chat.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MainChatComponent } from './main-chat.component'; + +describe('MainChatComponent', () => { + let component: MainChatComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MainChatComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MainChatComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/main-chat.component.ts b/src/app/components/main-chat/main-chat.component.ts new file mode 100644 index 0000000..a049916 --- /dev/null +++ b/src/app/components/main-chat/main-chat.component.ts @@ -0,0 +1,365 @@ +import { Component, ElementRef, Input } from '@angular/core'; +import { ChannleService } from '../../service/channle.service'; +import { MainComponent } from '../main/main.component'; +import { ChatService } from '../../service/chat.service'; +import { UserService } from '../../service/user.service'; +import { User } from '../../interface/user.interface'; +import { + Channel, + PrvChannel, + publicChannels, +} from '../../interface/channel.interface'; +import { Chat } from '../../interface/chat.interface'; +import { NavigationStart, Router } from '@angular/router'; +import { CommonModule } from '@angular/common'; +import { ChatContentComponent } from './chat-content/chat-content.component'; +import { SingleChatComponent } from './single-chat/single-chat.component'; +import { ToggleBooleanService } from '../../service/toggle-boolean.service'; +import { ChatMsgBoxComponent } from './chat-msg-box/chat-msg-box.component'; +import { FormsModule } from '@angular/forms'; +import { SmallBtnComponent } from '../../shared/components/small-btn/small-btn.component'; +import { ShowChannelMemberComponent } from './show-channel-member/show-channel-member.component'; +import { SharedService } from '../../service/shared.service'; +import { ChannelInformationsComponent } from './channel-informations/channel-informations.component'; +import { filter } from 'rxjs'; +import { OpenSendPrvMessageWindowComponent } from './show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component'; +import { HighlightPipe } from '../../highlight.pipe'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-main-chat', + standalone: true, + imports: [ + MainComponent, + CommonModule, + ChatContentComponent, + SingleChatComponent, + ChatMsgBoxComponent, + FormsModule, + SmallBtnComponent, + ShowChannelMemberComponent, + ChannelInformationsComponent, + OpenSendPrvMessageWindowComponent, + HighlightPipe, + TranslateModule, + ], + templateUrl: './main-chat.component.html', + styleUrl: './main-chat.component.scss', +}) +export class MainChatComponent { + @Input() currentChannel: string = ''; + @Input() isSecondaryChatOpen: boolean = false; + @Input() viewWidth: number = 0; + + firstLetter: string = ''; + openSearchWindow: boolean = false; + channelCreator: boolean = false; + openMenu: boolean = false; + showProfil: boolean = false; + talkToUser!: User[]; + routToPrvCHannel: boolean = false; + + constructor( + private route: Router, + public userService: UserService, + public channelService: ChannleService, + public chatService: ChatService, + public toggleBoolean: ToggleBooleanService, + private sharedService: SharedService + ) { + this.checkPrivatChatRouteEvent(); + this.routeToStartChannel(); + } + + RESPONSIVE_THRESHOLD_MOBILE = this.sharedService.RESPONSIVE_THRESHOLD_MOBILE; + + /** + * Sets the openMenu property based on the provided variable. + * @param {boolean} variable - The value to set for openMenu. + */ + closeEditEmitter(variable: boolean) { + this.openMenu = variable; + } + + /** + * Sets the showProfil property based on the provided value. + * @param {boolean} value - The value to set for showProfil. + */ + getShowProfilWindowBoolean(value: boolean) { + this.showProfil = value; + } + + /** + * Checks the route events for private chat messages. + */ + checkPrivatChatRouteEvent() { + this.route.events + .pipe( + filter( + (event): event is NavigationStart => event instanceof NavigationStart + ) + ) + .subscribe((event: NavigationStart) => { + const urlParts = this.route.url.split('/'); + const id = urlParts[urlParts.length - 1]; + this.hasPrivatChatMessages(id); + }); + } + + /** + * Checks if there are private chat messages for a given chat ID and performs necessary actions. + * @param {string} chatId - The ID of the chat. + */ + hasPrivatChatMessages(chatId: string) { + const isPrivatChannel = this.channelService.allPrvChannels.filter( + (user) => user.id === chatId + ); + if (isPrivatChannel.length > 0) { + const countMessages = this.chatService.allChats.filter( + (user) => user.channelId === chatId + ); + const userChannel = this.channelService.allPrvChannels.filter( + (user) => + user.creatorId === this.userService.getCurrentUserId() && + user.talkToUserId === this.userService.getCurrentUserId() && + user.id === chatId + ); + if (countMessages.length === 0 && userChannel.length === 0) { + this.chatService.deleteData(chatId, 'prv-channels'); + } + } + } + + /** + * Redirects to the start channel if the current channel is empty and the user is logged in. + */ + routeToStartChannel() { + if ( + this.currentChannel === '' && + this.userService.getCurrentUserId() !== undefined + ) { + this.route.navigateByUrl(`/main/${publicChannels[0]}`); + } + } + + /** + * Checks if the current user has access to any channels. + * @returns {Channel[]} Array of Channel objects that the user has access to. + */ + checkIfUserHasAccessToChannel() { + const isUserAChannelMember = this.channelService.allChannels.some( + (channel) => + channel.addedUser.includes(this.userService.getCurrentUserId()) + ); + + if (isUserAChannelMember) { + return this.channelService.allChannels.filter((channel) => + channel.addedUser.includes(this.userService.getCurrentUserId()) + ); + } + return []; + } + + /** + * Sets the openMenu property to true. + */ + showMenu() { + this.openMenu = true; + } + + /** + * Retrieves users associated with a chat ID. + * @param {string} chatId - The ID of the chat. + * @returns {User[]} Array of User objects associated with the chat ID. + */ + getChatUsers(chatId: string) { + const filteredTasks = this.userService.allUsers.filter( + (user) => user.id == chatId + ); + return filteredTasks; + } + + /** + * Retrieves chats associated with a chat ID. + * @param {string} chatId - The ID of the chat. + * @returns {Chat[]} Array of Chat objects associated with the chat ID. + */ + getChatChannel(chatId: string) { + const filteredTasks = this.chatService.allChats.filter( + (chat) => chat.channelId == chatId + ); + return filteredTasks; + } + + /** + * Retrieves channel information for a given channel ID. + * @param {string} chatId - The ID of the channel. + * @returns {Channel[]} Array of Channel objects matching the provided channel ID. + */ + getChannelName(chatId: string) { + const filteredTasks = this.channelService.allChannels.filter( + (channel) => channel.id == chatId + ); + return filteredTasks; + } + + /** + * Retrieves private chat information for a given private chat ID. + * @param {string} prvChatId - The ID of the private chat. + * @returns {PrvChannel[]} Array of PrvChannel objects matching the provided private chat ID. + */ + getPrvChat(prvChatId: string) { + const filteredChats = this.channelService.allPrvChannels.filter( + (prvChat) => prvChat.id == prvChatId + ); + this.getTalkToUser(filteredChats); + return filteredChats; + } + + /** + * Retrieves the user associated with a filtered private chat. + * @param {PrvChannel[]} filteredChat - The filtered private chat. + */ + getTalkToUser(filteredChat: PrvChannel[]) { + const talkToUser = filteredChat[0].talkToUserId; + const getUser = this.userService.allUsers.filter( + (user) => user.id === talkToUser + ); + if (getUser) { + this.talkToUser = getUser; + } + } + + /** + * Filters users based on the provided talkToUserId. + * @param {string} talkToUserId - The ID of the user to filter. + * @returns {User[]} Array of User objects matching the provided user ID. + */ + filterUser(talkToUserId: string) { + return this.userService.allUsers.filter((user) => user.id == talkToUserId); + } + + /** + * Checks the type of the current channel. + * @param {string} currentChannel - The ID of the current channel. + * @returns {string} Type of the current channel ('searchBar', 'allChannels', 'allPrvChannels'). + */ + checkCurrentChannel(currentChannel: string) { + if (currentChannel === 'searchBar') { + return 'searchBar'; + } + const allChannels = this.channelService.allChannels.some( + (channel) => channel.id == currentChannel + ); + const allPrvChannels = this.channelService.allPrvChannels.some( + (channel) => channel.id == currentChannel + ); + + if (allChannels) { + return 'allChannels'; + } else if (allPrvChannels) { + return 'allPrvChannels'; + } + return ''; + } + + /** + * Filters channels and users based on the input value. + * @param {string} inputValue - The input value to filter. + * @returns {string} Type of filtering ('filterChannel', 'filterUsers'). + */ + filterChannelAndUser(inputValue: string) { + const filterChannels = '#'; + const filterUsers = '@'; + this.firstLetter = inputValue[0]; + if (this.firstLetter == filterChannels) { + this.toggleBoolean.openSearchWindow = true; + return 'filterChannel'; + } else if (this.firstLetter == filterUsers) { + this.toggleBoolean.openSearchWindow = true; + return 'filterUsers'; + } + return (this.chatService.inputValue = ''); + } + + /** + * Sets the showProfil property to true. + */ + openUserProfil() { + this.showProfil = true; + } + + /** + * Chooses an element and performs necessary actions based on its type. + * @param {Channel | User} element - The element to choose. + */ + chooseElement(element: Channel | User) { + if ('firstName' in element) { + this.chatService.inputValue = `@${element.firstName} ${element.lastName}`; + const getUserID = element.id!; + this.routToPrvCHannel = true; + this.checkIfPrvChatExist(getUserID); + } else { + this.chatService.inputValue = `#${element.name}`; + this.chatService.getChannelId = element.id!; + } + this.toggleBoolean.openSearchWindow = false; + } + + /** + * Checks if a private chat exists for the provided user ID and performs necessary actions. + * @param {string} userID - The ID of the user. + */ + checkIfPrvChatExist(userID: string) { + const filterPrvChannelBoolean = this.channelService.allPrvChannels.some( + (chat) => chat.talkToUserId == userID + ); + if (!filterPrvChannelBoolean) { + this.userService.createPrvChannel(userID); + } else { + const filterPrvChannelValue = this.channelService.allPrvChannels.filter( + (chat) => chat.talkToUserId == userID + ); + this.chatService.getPrvChatId = filterPrvChannelValue[0].id!; + } + } + + /** + * Filters channels for a selected user. + * @param {string} currentChannel - The ID of the current channel. + * @returns {boolean} Boolean indicating if the channel is found. + */ + filterChannelForSelectedUser(currentChannel: string) { + const getBoolean = this.channelService.allChannels.some( + (channel) => channel.id == currentChannel + ); + const getAddedUsers = this.channelService.allChannels.filter( + (channel) => channel.id == currentChannel + ); + this.filterUsers(getAddedUsers[0].addedUser); + return getBoolean; + } + + /** + * Filters users based on an array of user IDs. + * @param {string[]} userArray - The array of user IDs to filter. + */ + filterUsers(userArray: string[]) { + this.userService.getFiltertUsers = []; + for (let i = 0; i < this.userService.allUsers.length; i++) { + const currentUser = this.userService.allUsers[i]; + if (userArray.includes(currentUser.id!)) { + this.userService.getFiltertUsers.push(currentUser); + } + } + } + + /** + * Opens the channel member window. + * @param {boolean} boolean - Boolean value to open or close the add member window. + */ + openMemberWindow(boolean: boolean) { + this.toggleBoolean.openChannelMemberWindow = true; + this.toggleBoolean.openAddMemberWindow(boolean); + } +} diff --git a/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.html b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.html new file mode 100644 index 0000000..d6866fb --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.html @@ -0,0 +1,91 @@ +
+
+ @if (showProfil) { + + @for(i of talkToUser; track i){ +
+
+

{{ 'open-send-prv-message.profil' | translate }}

+
+ +
+
+ +
+
+

{{ i.firstName }} {{ i.lastName }}

+
+ +
+ + @if (i.status) { +

{{ 'open-send-prv-message.aktiv' | translate }}

+ } @else { +

{{ 'open-send-prv-message.offline' | translate }}

+ } +
+ +
+ + +
+
+
+ } } @else { + + @for(i of user; track i){ +
+
+

{{ 'open-send-prv-message.profil' | translate }}

+
+ +
+
+ +
+
+

{{ i.firstName }} {{ i.lastName }}

+
+ +
+ + @if (i.status) { +

{{ 'open-send-prv-message.aktiv' | translate }}

+ } @else { +

{{ 'open-send-prv-message.offline' | translate }}

+ } +
+ +
+ + +
+
+ +
+ } } +
diff --git a/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.scss b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.scss new file mode 100644 index 0000000..bdd54d9 --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.scss @@ -0,0 +1,188 @@ +@import "../../../../../styles.scss"; + +.darkBackground { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + z-index: 4; +} + +.whiteBox { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 440px; + height: auto; + background-color: whitesmoke; + border-radius: 35px; + z-index: 15; + @include displayFlex(); + flex-direction: column; + padding-top: 32px; + .boxHeader { + width: 360px; + @include displayFlex($j: space-between); + p { + font-size: 24px; + font-weight: 700; + } + .positionCloseIcon { + width: 40px; + height: 40px; + @include displayFlex(); + margin-right: -10px; + transition: 0.3s ease-in-out; + &:hover { + background-color: #eceefe; + border-radius: 25px; + cursor: pointer; + > img { + filter: invert(59%) sepia(26%) saturate(871%) hue-rotate(199deg) + brightness(93%) contrast(100%); + } + } + } + } + .profileImg { + width: 200px; + height: 200px; + object-fit: cover; + border-radius: 50%; + margin: 24px; + } + > button { + @include displayFlex($g: 12px); + background-color: #676eee; + border: none; + border-radius: 25px; + padding: 12px; + padding-left: 22px; + padding-right: 22px; + font-size: larger; + font-weight: 500; + color: white; + margin: 32px; + margin-top: 0; + cursor: pointer; + transition: 0.3s ease-in-out; + &:hover { + background-color: #444df2; + box-shadow: rgba(0, 0, 0, 0.1) 0px 20px 25px -5px, + rgba(0, 0, 0, 0.04) 0px 10px 10px -5px; + } + } +} + +.detailsBox { + width: 360px; + .editBtnPosition { + @include displayFlex($j: space-between); + margin-bottom: 20px; + .name { + font-size: 32px; + font-weight: 700; + } + .editBtn { + color: #535af1; + cursor: pointer; + &:hover { + font-weight: 600; + } + } + } + .statusBox { + @include displayFlex($j: flex-start, $g: 12px); + margin-bottom: 40px; + > p { + margin: 0; + font-size: medium; + font-weight: 500; + } + } +} + +.fontColorGreen { + color: #92c83e; +} + +.emailBox { + @include displayFlex($j: flex-start, $a: flex-start, $g: 20px); + height: 96px; + margin-top: 24px; + img { + width: 25px; + height: 20px; + margin-top: 3px; + } + .email { + > p { + font-size: 20px; + font-weight: 600; + margin-bottom: 20px; + } + > a { + color: #4ea1ff; + font-size: 16px; + text-decoration: none; + margin-bottom: 20px; + background: linear-gradient(currentColor 0 0) bottom left/ + var(--underline-width, 0%) 0.1em no-repeat; + display: inline-block; + transition: background-size 0.5s; + &:hover { + --underline-width: 100%; + } + } + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .whiteBox { + width: 280px; + padding-top: 16px; + .boxHeader { + width: 230px; + p { + font-size: 21px; + font-weight: 700; + } + } + .profileImg { + width: 120px; + height: 120px; + margin: 20px; + } + } + .detailsBox { + width: 230px; + .editBtnPosition { + .name { + font-size: 24px; + font-weight: 700; + } + } + } + + .emailBox { + @include displayFlex($j: flex-start, $a: flex-start, $g: 10px); + img { + margin-top: 2px; + } + .email { + > p { + font-size: 18px; + font-weight: 600; + margin-bottom: 10px; + } + > a { + margin-bottom: 0; + } + } + } +} diff --git a/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.spec.ts b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.spec.ts new file mode 100644 index 0000000..e4699e8 --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OpenSendPrvMessageWindowComponent } from './open-send-prv-message-window.component'; + +describe('OpenSendPrvMessageWindowComponent', () => { + let component: OpenSendPrvMessageWindowComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [OpenSendPrvMessageWindowComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OpenSendPrvMessageWindowComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.ts b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.ts new file mode 100644 index 0000000..b0b1b48 --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/open-send-prv-message-window/open-send-prv-message-window.component.ts @@ -0,0 +1,100 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { User } from '../../../../interface/user.interface'; +import { ToggleBooleanService } from '../../../../service/toggle-boolean.service'; +import { ChannleService } from '../../../../service/channle.service'; +import { UserService } from '../../../../service/user.service'; +import { Router } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-open-send-prv-message-window', + standalone: true, + imports: [CommonModule, TranslateModule], + templateUrl: './open-send-prv-message-window.component.html', + styleUrl: './open-send-prv-message-window.component.scss', +}) +export class OpenSendPrvMessageWindowComponent { + @Input() user!: User[]; + @Input() talkToUser!: User[]; + @Input() openUserWindowBoolean!: boolean; + @Input() showProfil!: boolean; + @Output() closeUserWondow = new EventEmitter(); + @Output() showProfilWindow = new EventEmitter(); + isOnline: boolean = false; + + constructor( + public toggleBoolean: ToggleBooleanService, + private channelService: ChannleService, + public userService: UserService, + private route: Router + ) {} + + /** + * Closes the user window and profile window if open. + * Emits events to notify about window closure. + */ + closeWindow() { + this.openUserWindowBoolean = false; + this.showProfil = false; + this.closeUserWondow.emit(this.openUserWindowBoolean); + this.showProfilWindow.emit(this.showProfil); + } + + /** + * Closes all open windows and resets toggle booleans. + * Emits events to notify about window closures. + */ + closeEverything() { + this.openUserWindowBoolean = false; + this.closeUserWondow.emit(this.openUserWindowBoolean); + this.toggleBoolean.openChannelMemberWindow = false; + this.toggleBoolean.closeChannelMemberWindow = false; + } + + /** + * Routes to the user's private chat. + * If the chat channel does not exist, it creates one. + * @param {User[]} user - The user to route to. + */ + routeToUser(user: User[]) { + const userId = user[0].id!; + const channelExistsBoolean = this.channelService.allPrvChannels.some( + (channel) => + (channel.creatorId === userId && + channel.talkToUserId === this.userService.getCurrentUserId()) || + (channel.creatorId === this.userService.getCurrentUserId() && + channel.talkToUserId === userId) + ); + + if (!channelExistsBoolean) { + const createChannelPromise = this.userService.createPrvChannel(userId); + if (createChannelPromise instanceof Promise) { + createChannelPromise.then((docId) => { + this.route.navigateByUrl(`main/${docId}`); + }); + } + } else { + this.getRouteToPrvChat(userId, channelExistsBoolean); + } + this.closeEverything(); + } + + /** + * Routes to the existing private chat. + * @param {string} userId - The ID of the user to route to. + * @param {boolean} channelExistsBoolean - Indicates whether the chat channel exists. + */ + getRouteToPrvChat(userId: string, channelExistsBoolean: boolean) { + if (channelExistsBoolean) { + const existingChannel = this.channelService.allPrvChannels.find( + (channel) => + (channel.creatorId === userId && + channel.talkToUserId === this.userService.getCurrentUserId()) || + (channel.creatorId === this.userService.getCurrentUserId() && + channel.talkToUserId === userId) + ); + this.route.navigateByUrl(`main/${existingChannel!.id}`); + } + } +} diff --git a/src/app/components/main-chat/show-channel-member/show-channel-member.component.html b/src/app/components/main-chat/show-channel-member/show-channel-member.component.html new file mode 100644 index 0000000..dabce55 --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/show-channel-member.component.html @@ -0,0 +1,130 @@ +
+
+ @if (!toggleBoolean.closeChannelMemberWindow) { +
+
+

{{ "show-channel-member.header" | translate }}

+ +
+
+ @for(user of getFiltertUsers; track user){ +
+
+ + +
+

{{ user.firstName }} {{ user.lastName }}

+
+ } +
+
+ +

{{ "show-channel-member.addMember" | translate }}

+
+
+ } @else { +
+
+
+

{{ "show-channel-member.addMember" | translate }}

+ @if (getChannelName(currentChannel)) { + # {{ getCurrentChannelName }} + } +
+ +
+
+
+ +

{{ user.firstName }} {{ user.lastName }}

+ +
+
+
+ @if(getSearchedUser.length <= 0) { + {{ "show-channel-member.result" | translate }} } + @for(user of getSearchedUser; track user){ + @if(!isUserAlreadySelectet(user)) { +
+
+ + +
+

{{ user.firstName }} {{ user.lastName }}

+
+ } } +
+
+ +
+
+ +
+
+ } +
+ diff --git a/src/app/components/main-chat/show-channel-member/show-channel-member.component.scss b/src/app/components/main-chat/show-channel-member/show-channel-member.component.scss new file mode 100644 index 0000000..9da2dbb --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/show-channel-member.component.scss @@ -0,0 +1,344 @@ +@import "../../../../styles.scss"; + +.darkBackground { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + z-index: 3; +} + +.whiteBox { + position: absolute; + top: 199px; + right: 108px; + width: 320px; + height: fit-content; + z-index: 4; + border-radius: 35px; + border-top-right-radius: 0; + background-color: whitesmoke; + padding: 24px; + @include displayFlex($g: 20px); + flex-direction: column; + + .posiotionHeader { + @include displayFlex($j: space-between); + font-size: 24px; + font-weight: 600; + width: 100%; + } +} + +.positionOfAllUsersInBox { + @include displayFlex($j: flex-start, $a: flex-start); + flex-direction: column; + height: fit-content; + max-height: 300px; + overflow: auto; + width: 100%; + + .user { + @include displayFlex($g: 12px); + padding: 6px; + cursor: pointer; + transition: 0.2s ease-in-out; + + &:hover { + background-color: #edeefe; + border-radius: 25px; + } + + .positionImgs { + @include displayFlex($a: flex-end); + + .avatarImg { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 50%; + } + + .onlineIcon { + width: 12px; + height: 12px; + margin-left: -10px; + } + } + } +} + +.addMemberBox { + @include displayFlex($g: 20px); + transition: background-color 0.2s ease-in-out; + border-radius: 20px; + padding: 8px; + + &:hover { + background-color: #888dec; + cursor: pointer; + } +} + +.addMemberToChannelBox { + position: absolute; + top: 198px; + right: 62px; + width: 400px; + padding: 24px; + z-index: 3; + height: auto; + background-color: white; + border-radius: 35px; + border-top-right-radius: 0; + @include displayFlex($g: 20px); + flex-direction: column; + .posiotionHeader { + @include displayFlex($j: space-between, $a: flex-start); + width: 100%; + .headline { + @include displayFlex($a: flex-start, $g: 12px); + flex-direction: column; + p { + font-size: 24px; + font-weight: 600; + } + span { + font-size: 21px; + font-weight: 400; + color: #797ef3; + } + } + } +} + +.addedUserBox { + display: flex; + flex-wrap: wrap; + z-index: 4; + height: auto; + width: 100%; + border: 1px solid #888dec; + background-color: white; + border-radius: 25px; + transition: 0.3s ease-in-out; + position: relative; + + &:hover { + border: 1px solid #2c36f0; + } + .userPosition { + @include displayFlex($g: 8px); + padding: 4px; + padding-left: 8px; + padding-right: 8px; + background-color: #edeefe; + border-radius: 25px; + border-radius: 25px; + margin: 4px; + p { + font-size: 21px; + } + .avatarImg { + width: 32px; + height: 32px; + object-fit: cover; + border-radius: 50%; + } + + .imgClose { + width: 12px; + object-fit: contain; + transition: 0.1s ease-in-out; + cursor: pointer; + + &:hover { + scale: 1.1; + filter: brightness(0) saturate(100%) invert(8%) sepia(96%) + saturate(6339%) hue-rotate(1deg) brightness(102%) contrast(109%); + } + } + } + + .inputfieldStyle { + width: 100%; + flex-grow: 1; + outline: none; + border: none; + border-radius: 25px; + height: 26px; + padding: 12px; + height: auto; + font-size: larger; + } +} + +.showSearchedUsersWindow::-webkit-scrollbar { + display: none; +} + +.showSearchedUsersWindow { + position: absolute; + top: 88%; + left: 20px; + z-index: 3; + padding: 4px; + border: 1px solid #888dec; + border-radius: 25px; + border-top-left-radius: 0; + background-color: white; + overflow: auto; + max-height: 210px; + width: fit-content; + max-width: 240px; + scrollbar-width: none; + -ms-overflow-style: none; + text-align: start; + .positionOfAllUsersBox { + @include displayFlex($a: flex-start); + flex-direction: column; + overflow: auto; + width: 100%; + span { + font-size: 20px; + font-weight: 400; + padding: 6px; + } + .userBox { + @include displayFlex($g: 12px); + padding: 6px; + cursor: pointer; + p { + font-size: 21px; + } + &:hover { + background-color: #edeefe; + border-radius: 25px; + } + + .positionImgsBox { + @include displayFlex($a: flex-end); + + .addAvatarImg { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 50%; + } + + .onlineIcon { + width: 12px; + height: 12px; + margin-left: -10px; + } + } + } + } +} + +.positionCreateBtn { + width: 100%; + @include displayFlex($j: flex-end); +} + +.furterBtnClass { + width: 120px; + height: 48px; + background-color: white; + border: 1px solid #888dec; + border-radius: 25px; + font-size: larger; + color: #444df2; + transition: 0.3s ease-in-out; + &:hover { + background-color: #444df2; + color: white; + cursor: pointer; + } +} + +.disabledBtn { + background-color: #22222242; + border: none; + font-size: larger; + color: #fff; + width: 120px; + height: 48px; + border-radius: 25px; + font-size: larger; + transition: 0.3s ease-in-out; +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .whiteBox { + top: 140px; + right: 20px; + width: 250px; + .posiotionHeader { + font-size: 21px; + } + } + + .addMemberToChannelBox { + position: absolute; + top: 140px; + right: 20px; + width: 230px; + .posiotionHeader { + .headline { + p { + font-size: 21px; + } + span { + font-size: 18px; + } + } + } + } + + .showSearchedUsersWindow { + position: absolute; + top: 88%; + right: 0px; + max-height: 210px; + width: 200px; + .positionOfAllUsersBox { + span { + font-size: 18px; + } + .userBox { + p { + font-size: 18px; + font-style: 600; + } + .positionImgsBox { + .addAvatarImg { + width: 32px; + height: 32px; + } + .onlineIcon { + width: 9px; + height: 9px; + margin-left: -8px; + } + } + } + } + } +} + +@media screen and (max-height: 600px) { + .positionOfAllUsersInBox { + max-height: 250px; + } +} + +@media screen and (max-height: 500px) { + .positionOfAllUsersInBox { + max-height: 170px; + } +} diff --git a/src/app/components/main-chat/show-channel-member/show-channel-member.component.spec.ts b/src/app/components/main-chat/show-channel-member/show-channel-member.component.spec.ts new file mode 100644 index 0000000..733999a --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/show-channel-member.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ShowChannelMemberComponent } from './show-channel-member.component'; + +describe('ShowChannelMemberComponent', () => { + let component: ShowChannelMemberComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShowChannelMemberComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShowChannelMemberComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/show-channel-member/show-channel-member.component.ts b/src/app/components/main-chat/show-channel-member/show-channel-member.component.ts new file mode 100644 index 0000000..fe29938 --- /dev/null +++ b/src/app/components/main-chat/show-channel-member/show-channel-member.component.ts @@ -0,0 +1,193 @@ +import { Component, Input } from '@angular/core'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; +import { CommonModule } from '@angular/common'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { User } from '../../../interface/user.interface'; +import { FormsModule } from '@angular/forms'; +import { ChannleService } from '../../../service/channle.service'; +import { UserService } from '../../../service/user.service'; +import { OpenSendPrvMessageWindowComponent } from './open-send-prv-message-window/open-send-prv-message-window.component'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-show-channel-member', + standalone: true, + imports: [ + CommonModule, + SmallBtnComponent, + FormsModule, + OpenSendPrvMessageWindowComponent, + TranslateModule, + ], + templateUrl: './show-channel-member.component.html', + styleUrl: './show-channel-member.component.scss', +}) +export class ShowChannelMemberComponent { + @Input() isSecondaryChatOpen: boolean = false; + + userName: string = ''; + showExistenUsers: boolean = false; + getSearchedUser: User[] = []; + getCurrentChannelName: string = ''; + getSelectedUsers: User[] = []; + selectedUsers: string[] = []; + + openUserWindowBoolean: boolean = false; + user: User[] = []; + + @Input() getFiltertUsers!: User[]; + @Input() currentChannel!: string; + + constructor( + public toggleBoolean: ToggleBooleanService, + public channelService: ChannleService, + public userService: UserService + ) {} + + /** + * Closes the channel member window and resets related values. + */ + closeChannelMemberWindow() { + this.toggleBoolean.openChannelMemberWindow = false; + this.toggleBoolean.closeChannelMemberWindow = false; + this.resetValues(); + } + + /** + * Filters users based on search value and updates the list of searched users. + * @param {string} searchValue - The value to search for. + */ + filterUsers(searchValue: string) { + if (searchValue != '') { + this.showExistenUsers = true; + this.getSearchedUser = []; + const searchedUser = searchValue.toLowerCase().trim(); + const filteredUsers = this.userService.getUsers().filter((user) => { + const fullName = `${user.firstName} ${user.lastName}`.toLowerCase(); + return fullName.includes(searchedUser); + }); + this.checkIfUserIsInChannel(filteredUsers); + } + } + + /** + * Checks if users from the filtered list are already in the current channel and updates the searched user list. + * @param {User[]} filteredUsers - The list of filtered users. + */ + checkIfUserIsInChannel(filteredUsers: User[]) { + const getChannel = this.channelService.allChannels.filter( + (channel) => channel.id === this.currentChannel + ); + + for (const user of getChannel) { + const userArray = user.addedUser; + this.channelService.channelMembers = userArray; + + for (const user of filteredUsers) { + const isUserInChannel = userArray.some( + (channelUser) => channelUser === user.id + ); + if (!isUserInChannel) { + this.getSearchedUser.push(user); + } + } + } + } + + /** + * Checks if a user is already selected. + * @param {User} user - The user to check. + * @returns {boolean} Returns true if the user is already selected, otherwise false. + */ + isUserAlreadySelectet(user: User) { + return this.getSelectedUsers.some( + (selectedUser) => selectedUser.id === user.id + ); + } + + /** + * Adds a user to the list of selected users. + * @param {User} user - The user to add. + */ + chooseUser(user: User) { + const isUserAlreadySelected = this.getSelectedUsers.some( + (selectedUser) => selectedUser.id === user.id + ); + + if (!isUserAlreadySelected) { + this.selectedUsers.push(user.id!); + this.getSelectedUsers.push(user); + } + this.userName = ''; + this.showExistenUsers = false; + } + + /** + * Removes the user at the specified index from the list of selected users. + * @param {number} index - The index of the user to remove. + */ + spliceCurrentUser(index: number) { + this.getSelectedUsers.splice(index, 1); + this.showExistenUsers = false; + } + + /** + * Gets the name of the current channel. + * @param {string} currentChannel - The ID of the current channel. + * @returns {boolean} Returns true if the channel exists, otherwise false. + */ + getChannelName(currentChannel: string) { + const getName = this.channelService.allChannels.some( + (channel) => channel.id == currentChannel + ); + const getChannelName = this.channelService.allChannels.filter( + (channel) => channel.id == currentChannel + ); + this.getCurrentChannelName = getChannelName[0].name; + return getName; + } + + /** + * Adds selected users to the current channel. + */ + addUserToChannel() { + this.channelService.addNewMemberToChannel( + 'channels', + this.currentChannel, + this.selectedUsers, + 'addUserToChannel' + ); + this.closeChannelMemberWindow(); + } + + /** + * Opens a user window. + * + * @param {User} user - The user to be displayed in the window. + * @returns {void} + */ + openUserWindow(user: User) { + this.user = [user]; + this.openUserWindowBoolean = !this.openUserWindowBoolean; + } + + /** + * Opens or closes the user window based on the given value. + * @param {boolean} value - The value to set for opening/closing the user window. + */ + changeOpenUserWindowBoolean(value: boolean) { + this.openUserWindowBoolean = value; + } + + /** + * Resets various values used in the component. + */ + resetValues() { + this.userName = ''; + this.showExistenUsers = false; + this.getSearchedUser = []; + this.getCurrentChannelName = ''; + this.getSelectedUsers = []; + this.selectedUsers = []; + } +} diff --git a/src/app/components/main-chat/single-chat/attachments/attachments.component.html b/src/app/components/main-chat/single-chat/attachments/attachments.component.html new file mode 100644 index 0000000..d202528 --- /dev/null +++ b/src/app/components/main-chat/single-chat/attachments/attachments.component.html @@ -0,0 +1,68 @@ + +
+
+
+
+
+
+ @if (['png', 'jpg', 'jpeg', 'gif'].includes(getFileType(file))) { + image + } @if (['pdf', 'doc', 'txt'].includes(getFileType(file))) { + + image + } @if (['mp3', 'wav', 'wma'].includes(getFileType(file))) { + + }@if (getFileType(file) === 'mp4') { +
+ +
+ } +
+
+
+
+
+
diff --git a/src/app/components/main-chat/single-chat/attachments/attachments.component.scss b/src/app/components/main-chat/single-chat/attachments/attachments.component.scss new file mode 100644 index 0000000..c824f3a --- /dev/null +++ b/src/app/components/main-chat/single-chat/attachments/attachments.component.scss @@ -0,0 +1,71 @@ +@import "./../../../../../styles.scss"; + +.files { + display: flex; + + max-width: calc(100vw - 140px); + overflow: auto; + .filesView { + cursor: pointer; + transition: 0.3s ease-in-out; + filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.3)); + img, + video { + height: 7.5vw; + min-height: 80px; + width: auto; + border-radius: 12px; + } + .otherFiles { + height: 5vw; + min-height: 60px; + width: auto; + border-radius: 12px; + } + &:hover { + filter: drop-shadow(5px 5px 5px rgba(0, 0, 0, 0.35)); + } + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: 510px) { + .files { + .filesView { + audio { + width: 250px; + } + } + } +} + +@media screen and (max-width: 460px) { + .files { + .filesView { + audio { + width: 200px; + } + } + } +} + +@media screen and (max-width: 410px) { + .files { + .filesView { + audio { + width: 150px; + } + } + } +} + +@media screen and (max-width: 360px) { + .files { + .filesView { + audio { + width: 90px; + } + } + } +} diff --git a/src/app/components/main-chat/single-chat/attachments/attachments.component.spec.ts b/src/app/components/main-chat/single-chat/attachments/attachments.component.spec.ts new file mode 100644 index 0000000..4aeb48c --- /dev/null +++ b/src/app/components/main-chat/single-chat/attachments/attachments.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AttachmentsComponent } from './attachments.component'; + +describe('AttachmentsComponent', () => { + let component: AttachmentsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AttachmentsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AttachmentsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/single-chat/attachments/attachments.component.ts b/src/app/components/main-chat/single-chat/attachments/attachments.component.ts new file mode 100644 index 0000000..13a1eba --- /dev/null +++ b/src/app/components/main-chat/single-chat/attachments/attachments.component.ts @@ -0,0 +1,54 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { DownloadFilesService } from '../../../../service/download-files.service'; +import { OverlayService } from '../../../../service/overlay.service'; +import { OverlayComponent } from '../../../../shared/components/overlay/overlay.component'; +import { SharedService } from '../../../../service/shared.service'; + +@Component({ + selector: 'app-attachments', + standalone: true, + imports: [CommonModule, OverlayComponent], + templateUrl: './attachments.component.html', + styleUrl: './attachments.component.scss', +}) +export class AttachmentsComponent { + @Input() chatId: string = ''; + @Input() openOnSecondaryChat: boolean = false; + @Input() viewWidth: number = 0; + imageUrl: string = ''; + + constructor( + public downloadFilesService: DownloadFilesService, + private overlayService: OverlayService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + + // Type of files: + // Img: PNG, GIF, JPG, JPEG + // Files: PDF, DOC, TXT + // Audio: MP3, WMA, WAV + // Video: MP4 + + /** + * Gets the file type from the given file name. + * @param {string} file - The name of the file. + * @returns {string} The file type extracted from the file name. + */ + getFileType(file: string): string { + const extension = file.split('.').pop()?.toLowerCase(); + const getTag = extension!.split('?')[0]; + return getTag || ''; + } + + /** + * Shows an overlay using the provided file name. + * @param {string} file - The name of the file to display in the overlay. + * @returns {void} + */ + showOverlay(file: string) { + this.overlayService.setOverlayData(file); + } +} diff --git a/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.html b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.html new file mode 100644 index 0000000..91ba9df --- /dev/null +++ b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.html @@ -0,0 +1,65 @@ +
+ + + @if(isEmojiPickerVisible) { + + } + +
+ + diff --git a/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.scss b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.scss new file mode 100644 index 0000000..608fe1e --- /dev/null +++ b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.scss @@ -0,0 +1,162 @@ +@import "../../../../../styles.scss"; + +form { + position: relative; + width: calc(100% - 24px); + textarea { + width: calc(100% - 6px); + height: 100px; + border: 0; + border-radius: 20px; + font-size: 18px; + font-weight: 400; + padding: 12px; + resize: none; + &:focus { + outline: none; + } + &:invalid { + border: 1px solid red; + } + } +} + +app-emoji-picker { + position: absolute; + bottom: 50px; + left: 20px; + z-index: 5; +} + +app-small-btn { + padding: 9px; +} + +.footer { + display: flex; + justify-content: space-between; + align-items: end; + width: 100%; +} + +.btns { + padding: 12px 0; + .btn { + padding: 9px 15px; + border-radius: 50px; + border: 1px solid #6971f5; + background-color: #6971f5; + color: #fff; + font-size: 18px; + font-weight: 700; + cursor: pointer; + &:disabled { + background-color: #686868; + } + &:first-child { + margin-right: 12px; + background-color: #fff; + color: #6971f5; + } + &:hover { + background-color: #444df2; + border-color: #444df2; + color: #fff; + &:disabled { + background-color: #686868; + } + } + } +} + +.interactIcons { + cursor: pointer; + transition: filter 0.3s ease; + padding: 8px; + &:hover { + scale: 1.1; + background-color: #b7bae7; + border-radius: 50%; + filter: brightness(120%); + } +} + +.disabledIcon { + filter: brightness(0) saturate(100%) invert(45%) sepia(75%) saturate(684%) + hue-rotate(204deg) brightness(101%) contrast(91%); +} + +.files { + position: absolute; + padding-top: 12px; + top: 0; + right: -24px; +} + +.fileBox { + border: 1px solid #e5e5e5; + border-radius: 10px; + padding: 5px 10px; + margin-bottom: 6px; + background-color: #eee; + max-width: 40px; + max-height: 20px; + margin-right: 12px; + position: relative; + display: flex; + justify-content: center; + align-items: center; + .fileIcons { + margin-left: 12px; + margin-right: 12px; + cursor: pointer; + &:hover { + filter: brightness(0) saturate(100%) invert(20%) sepia(40%) + saturate(6312%) hue-rotate(236deg) brightness(106%) contrast(90%); + } + } +} + +.closeIcon { + position: absolute; + top: -4px; + right: -4px; + width: 16px; + object-fit: contain; + cursor: pointer; + &:hover { + filter: brightness(0) saturate(100%) invert(20%) sepia(78%) saturate(5090%) + hue-rotate(5deg) brightness(105%) contrast(103%); + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .btns { + padding: 6px 0; + .btn { + padding: 6px 12px; + border-radius: 40px; + font-size: 14px; + &:first-child { + margin-right: 6px; + } + } + } + + app-small-btn { + padding: 6px; + } + + form { + width: calc(100% - 12px); + } +} + +@media screen and (max-width: 360px) { + .btns { + .btn { + padding: 4px 8px; + font-size: 12px; + } + } +} diff --git a/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.spec.ts b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.spec.ts new file mode 100644 index 0000000..9183647 --- /dev/null +++ b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditMsgComponent } from './edit-msg.component'; + +describe('EditMsgComponent', () => { + let component: EditMsgComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [EditMsgComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(EditMsgComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.ts b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.ts new file mode 100644 index 0000000..6ea074f --- /dev/null +++ b/src/app/components/main-chat/single-chat/edit-msg/edit-msg.component.ts @@ -0,0 +1,160 @@ +import { + Component, + EventEmitter, + HostListener, + Input, + Output, +} from '@angular/core'; +import { + Chat, + ChatAnswers, + ChatReactions, +} from '../../../../interface/chat.interface'; +import { SingleChatComponent } from '../single-chat.component'; +import { CommonModule } from '@angular/common'; +import { FormsModule, NgForm } from '@angular/forms'; +import { ChatService } from '../../../../service/chat.service'; +import { PickerComponent } from '@ctrl/ngx-emoji-mart'; +import { SmallBtnComponent } from '../../../../shared/components/small-btn/small-btn.component'; +import { DownloadFilesService } from '../../../../service/download-files.service'; +import { EmojiPickerComponent } from '../../../../shared/components/emoji-picker/emoji-picker.component'; +import { UserService } from '../../../../service/user.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { SharedService } from '../../../../service/shared.service'; + +@Component({ + selector: 'app-edit-msg', + standalone: true, + imports: [ + CommonModule, + FormsModule, + SingleChatComponent, + PickerComponent, + SmallBtnComponent, + EmojiPickerComponent, + TranslateModule, + ], + templateUrl: './edit-msg.component.html', + styleUrl: './edit-msg.component.scss', +}) +export class EditMsgComponent { + @Input() chat!: Chat | ChatAnswers; + @Input() viewWidth: number = 0; + @Input() openOnSecondaryChat: boolean = false; + @Output() closeEditMsgEmitter: EventEmitter = + new EventEmitter(); + + isEmojiPickerVisible: boolean | undefined; + public originalMessage: string = ''; + + constructor( + public chatService: ChatService, + public downloadFilesService: DownloadFilesService, + public userService: UserService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + RESPONSIVE_THRESHOLD_MOBILE = this.sharedService.RESPONSIVE_THRESHOLD_MOBILE; + + ngOnInit() { + this.originalMessage = this.chat.message as string; + } + + /** + * Restore the original message and emit an event to close the edit message form. + */ + closeEditMsg() { + this.chat.message = this.originalMessage; + this.closeEditMsgEmitter.emit(false); + } + + /** + * Submit the edited message and update the chat. + * @param {string} chatId - The ID of the chat. + * @param {NgForm} form - The form containing the edited message. + */ + onSubmit(chatId: string, form: NgForm) { + this.chatService.updateChat(chatId, form.value); + this.closeEditMsg(); + } + + /** + * Submit the message when the Enter key is pressed. + * @param {KeyboardEvent} e - The keyboard event. + * @param {string} chatId - The ID of the chat. + * @param {NgForm} form - The form containing the message. + */ + sendMessageWithEnter(e: KeyboardEvent, chatId: string, form: NgForm) { + if (e.keyCode === 13) { + this.onSubmit(chatId, form); + } + } + + // EMOJI + + /** + * Add an emoji to the message. + * @param {any} $event - The emitted event containing the emoji. + */ + emojiOutputEmitter($event: any) { + this.addEmoji($event); + } + + /** + * Add an emoji to the message. + * @param {any} event - The emitted event containing the emoji. + */ + public addEmoji(event: any) { + this.chat.message = `${this.chat.message}${event}`; + this.isEmojiPickerVisible = false; + } + + /** + * Toggle the visibility of the emoji picker. + */ + toggleEmojiPicker() { + this.isEmojiPickerVisible = !this.isEmojiPickerVisible; + } + + // FILES + + /** + * Open the file in a new tab. + * @param {string} filePath - The path to the file. + */ + showCurrentFile(filePath: string) { + const url = filePath; + window.open(url, '_blank'); + } + + /** + * Get the type of file based on its extension. + * @param {string} filePath - The path to the file. + * @returns {string} - The path to the corresponding file icon. + */ + getFileType(filePath: string): string { + const fileName = filePath.split('?')[0].split('/').pop(); + + if (fileName) { + if (fileName.endsWith('.mp3')) { + return 'assets/img/mp3Icon.svg'; + } else if (fileName.endsWith('.jpg' || '.jpeg' || '.png' || '.gif')) { + return 'assets/img/imgIcon.svg'; + } else if (fileName.endsWith('.pdf' || '.doc' || '.txt')) { + return 'assets/img/pdfIcon.svg'; + } else if (fileName.endsWith('.mp4' || '.avi')) { + return 'assets/img/videoIcon.svg'; + } + } + return 'assets/img/documentIcon.svg'; + } + + /** + * Delete a file. + * @param {string} file - The file to be deleted. + */ + deleteFile(file: string) { + console.log('Deleted:' + file); + } +} diff --git a/src/app/components/main-chat/single-chat/options-menu/options-menu.component.html b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.html new file mode 100644 index 0000000..b2b3fc2 --- /dev/null +++ b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.html @@ -0,0 +1,137 @@ +
+ @if (!openOnSecondaryChat) { +
+ + + + + + + @if (!isPrivatChannel) { + + + } @if (user.id === userService.getCurrentUserId()) { + + + } +
+ + } @else { +
+ + @if (user.id === userService.getCurrentUserId()) { + + + } +
+ + } @if(isEmojiPickerVisible) { + + } +
diff --git a/src/app/components/main-chat/single-chat/options-menu/options-menu.component.scss b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.scss new file mode 100644 index 0000000..dd15bc9 --- /dev/null +++ b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.scss @@ -0,0 +1,137 @@ +@import "./../../../../../styles.scss"; + +.content { + display: flex; + align-items: center; + justify-content: center; + position: relative; + max-width: 256px; + width: fit-content; + height: 46px; + background-color: #fff; + padding: 3px 15px 3px 20px; + border: 1px solid rgba(0, 0, 0, 0.2); + border-top-left-radius: 25px; + border-top-right-radius: 25px; + border-bottom-left-radius: 25px; +} + +.nav { + display: flex; + align-items: center; + justify-content: center; + width: fit-content; + white-space: nowrap; + position: absolute; + top: 52px; + right: 0; + background-color: #fff; + padding: 10px 20px; + border: 1px solid rgba(0, 0, 0, 0.2); + border-top-left-radius: 30px; + border-bottom-left-radius: 30px; + border-bottom-right-radius: 30px; + p { + font-size: 21px; + font-weight: 600; + padding: 10px 20px; + border-radius: 30px; + cursor: pointer; + &:hover { + color: #545af1; + background-color: #edeefe; + } + &:nth-child(2) { + &:hover { + color: #fff; + background-color: #ed1f79; + } + } + } +} + +.navbar { + display: flex; + flex-direction: column; +} + +app-emoji-picker { + position: absolute; + top: 53px; + left: -80px; + z-index: 5; +} + +app-small-btn { + padding: 0 8px; +} + +.d-none { + display: none; +} + +.mirror { + transform: scaleX(-1); +} + +.secondaryChatPickerOffset { + left: -190px !important; +} + +/*------------- ANIMATION -------------*/ + +.animation-coming-in { + animation: coming-in 125ms ease-in-out forwards; +} + +.animation-coming-out { + animation: coming-out 125ms ease-in-out forwards; +} + +@keyframes coming-in { + 0% { + opacity: 0; + transform: translateY(-30px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes coming-out { + 0% { + opacity: 1; + transform: translateY(0); + } + 100% { + opacity: 0; + transform: translateY(-30px); + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .content { + height: 32px; + padding: 2px 10px 2px 14px; + border-top-left-radius: 17px; + border-top-right-radius: 17px; + border-bottom-left-radius: 17px; + } + + .nav { + top: 37px; + padding: 7px 14px; + border-top-left-radius: 21px; + border-bottom-left-radius: 21px; + border-bottom-right-radius: 21px; + p { + font-size: 18px; + font-weight: 600; + padding: 7px 14px; + border-radius: 21px; + } + } +} diff --git a/src/app/components/main-chat/single-chat/options-menu/options-menu.component.spec.ts b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.spec.ts new file mode 100644 index 0000000..3914d34 --- /dev/null +++ b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OptionsMenuComponent } from './options-menu.component'; + +describe('OptionsMenuComponent', () => { + let component: OptionsMenuComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [OptionsMenuComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OptionsMenuComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/single-chat/options-menu/options-menu.component.ts b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.ts new file mode 100644 index 0000000..5e0ac67 --- /dev/null +++ b/src/app/components/main-chat/single-chat/options-menu/options-menu.component.ts @@ -0,0 +1,200 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { SingleChatComponent } from '../single-chat.component'; +import { SmallBtnComponent } from '../../../../shared/components/small-btn/small-btn.component'; +import { ChatService } from '../../../../service/chat.service'; +import { EmojiPickerComponent } from '../../../../shared/components/emoji-picker/emoji-picker.component'; +import { UserService } from '../../../../service/user.service'; +import { ChatReactions } from '../../../../interface/chat.interface'; +import { User } from '../../../../interface/user.interface'; +import { SharedService } from '../../../../service/shared.service'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-options-menu', + standalone: true, + imports: [ + CommonModule, + SingleChatComponent, + SmallBtnComponent, + EmojiPickerComponent, + TranslateModule, + ], + templateUrl: './options-menu.component.html', + styleUrl: './options-menu.component.scss', +}) +export class OptionsMenuComponent { + @Input() user: User = {} as User; + @Input() currentChat: string = ''; + @Input() openOnSecondaryChat: boolean = false; + @Input() isPrivatChannel: boolean = false; + @Input() viewWidth: number = 0; + @Output() editMsgEmitter: EventEmitter = new EventEmitter(); + + isNavOpen: boolean = false; + isEmojiPickerVisible: boolean = false; + + constructor( + public chatService: ChatService, + public userService: UserService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD_MOBILE = this.sharedService.RESPONSIVE_THRESHOLD_MOBILE; + + /** + * Emits signal to edit message and toggles navigation. + */ + editMsg() { + this.editMsgEmitter.emit(true); + this.toggleNav(); + } + + /** + * Deletes message from specified database and toggles navigation. + * @param {string} database - The name of the database to delete from. + */ + deleteMsg(database: string) { + this.toggleNav(); + this.chatService.deleteData(this.currentChat, database); + } + + /** + * Emits emoji output event for a chat message. + * @param {*} $event - The event containing the emoji. + * @param {string} chatId - The ID of the chat message. + */ + emojiOutputEmitter($event: any, chatId: string) { + if (!this.checkExistEmojiOnChat(chatId, $event)) { + this.addNewReaction($event, chatId); + } + } + + /** + * Adds reaction icon to a chat message. + * @param {string} icon - The icon to add as reaction. + * @param {string} chatId - The ID of the chat message. + */ + addReactionIcon(icon: string, chatId: string) { + if (!this.checkExistEmojiOnChat(chatId, icon)) { + this.addNewReaction(icon, chatId); + } else { + const id = this.getReactionIcon(chatId, icon)[0].id; + if (id != undefined) { + this.toggleEmoji(id); + } + } + } + + /** + * Adds a new reaction to a chat message. + * @param {*} event - The event containing the reaction. + * @param {string} chatId - The ID of the chat message. + */ + addNewReaction(event: any, chatId: string) { + let reaction: ChatReactions = { + chatId: chatId, + icon: event, + userId: [this.userService.getCurrentUserId()], + }; + const { id, ...reactionWithoutId } = reaction; + this.chatService.createNewReaction(reactionWithoutId); + } + + /** + * Checks if a specific emoji exists on a chat message. + * @param {string} chatId - The ID of the chat message. + * @param {string} icon - The icon to check for existence. + * @returns {boolean} - True if the emoji exists, false otherwise. + */ + checkExistEmojiOnChat(chatId: string, icon: string) { + return this.getReaction(chatId).length > 0 && + this.getReactionIcon(chatId, icon).length > 0 + ? true + : false; + } + + /** + * Retrieves all reactions for a chat message. + * @param {string} chatId - The ID of the chat message. + * @returns {Array} - Array of reactions for the chat message. + */ + getReaction(chatId: string) { + return this.chatService.allChatReactions.filter( + (reaction) => reaction.chatId === chatId + ); + } + + /** + * Retrieves reactions with a specific icon for a chat message. + * @param {string} chatId - The ID of the chat message. + * @param {string} icon - The icon to filter reactions. + * @returns {Array} - Array of reactions with the specified icon. + */ + getReactionIcon(chatId: string, icon: string) { + const chat = this.getReaction(chatId); + return chat.filter((reaction) => reaction.icon == icon); + } + + /** + * Emits signal to toggle emoji picker visibility. + * @param {*} $event - The event containing the visibility state. + */ + emojiVisibleEmitter($event: any) { + this.isEmojiPickerVisible = $event; + } + + /** + * Toggles the navigation bar state. + */ + toggleNav() { + this.isNavOpen = !this.isNavOpen; + this.isEmojiPickerVisible = false; + } + + /** + * Toggles the secondary chat display. + * @param {string} chatId - The ID of the chat message. + */ + toggleSecondaryChat(chatId: string) { + this.chatService.toggleSecondaryChat(chatId); + this.isEmojiPickerVisible = false; + } + + /** + * Toggles the visibility of the emoji picker. + */ + toggleEmojiPicker() { + this.isEmojiPickerVisible = !this.isEmojiPickerVisible; + } + + /** + * Retrieves the document ID for a reaction. + * @param {string} chatId - The ID of the chat message. + * @returns {Array} - Array containing the reaction document ID. + */ + getReactionDocId(chatId: string) { + return this.chatService.allChatReactions.filter( + (reaction) => reaction.id === chatId + ); + } + + /** + * Toggles the reaction of a user on a chat message. + * @param {string} reactionID - The ID of the reaction. + */ + toggleEmoji(reactionID: string) { + const userIds = this.getReactionDocId(reactionID)[0].userId; + if (userIds.includes(this.userService.getCurrentUserId())) { + userIds.splice(userIds.indexOf(this.userService.getCurrentUserId()), 1); + if (userIds.length == 0) { + this.chatService.deleteData(reactionID, 'reactions'); + } else { + this.chatService.updateReaction(reactionID, userIds); + } + } else { + userIds.push(this.userService.getCurrentUserId()); + this.chatService.updateReaction(reactionID, userIds); + } + } +} diff --git a/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.html b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.html new file mode 100644 index 0000000..fc9572d --- /dev/null +++ b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.html @@ -0,0 +1,91 @@ +
+ + + @if(isEmojiPickerVisible) { + + } +
+ @for (reaction of getReaction(chat.id); track reaction; let i = $index) { + @if (reaction.id) { +
+ @if (reaction.icon === "okay" || reaction.icon === "clap-hands") { + + } @else { + + + } + {{ reaction.userId.length }} +
+ } } +
+ + + + @if (reactionDialogId != '') { @for (reaction of + getReactionDocId(reactionDialogId); track reaction) { +
+
+ @if (reaction.icon === "okay" || reaction.icon === "clap-hands") { + + } @else { + + } +
+
+ @for (reactionUId of getReactionDocId(reactionDialogId)[0].userId; track + reactionUId;) { +
+ {{ getUserId(reactionUId)[0].firstName }} + {{ getUserId(reactionUId)[0].lastName }} + @if (getUserId(reactionUId)[0].id == userService.getCurrentUserId()) { + (You)} +
+ } +
+ @if (getReactionDocId(reactionDialogId)[0].userId.length > 1) { +

{{ "reaction-emojis.react" | translate }}

+ } @else { +

{{ "reaction-emojis.react2" | translate }}

+ } +
+ } } +
diff --git a/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.scss b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.scss new file mode 100644 index 0000000..0cb7b78 --- /dev/null +++ b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.scss @@ -0,0 +1,134 @@ +@import "../../../../../styles.scss"; + +section { + display: flex; + position: relative; +} + +.emojiSection { + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.emoji { + display: flex; + align-items: center; + justify-content: center; + margin: 6px; + background-color: #fff; + width: 44px; + height: 30px; + padding: 5px 12px; + border-radius: 20px; + border: 1px solid #adb0d9; + transition: 0.125s ease-in-out; + cursor: pointer; + img { + height: 24px; + width: auto; + } + span { + font-size: 16px; + font-weight: 400; + padding-left: 6px; + } + &:hover { + border-color: #444df2; + } +} + +.dialog { + position: fixed; + min-width: 158px; + width: fit-content; + min-height: 112px; + height: fit-content; + max-height: 300px; + padding: 15px 10px; + border-radius: 30px 0px 30px 30px; + z-index: 5; + background-color: #444df2; + .icon { + display: flex; + justify-content: center; + margin: 6px 0; + img { + width: 30px; + height: 30px; + } + } + .name { + padding: 6px 0; + font-size: 18px; + font-weight: 700; + color: #fff; + text-align: center; + .user { + padding: 2px 0; + } + } + p { + font-size: 16px; + font-weight: 400; + color: #fff; + text-align: center; + } +} + +.mirror { + transform: scaleX(-1); +} + +.emojiPickerFirstMsg { + position: absolute; + top: 50px; + left: 20px; + z-index: 3; + width: fit-content; +} + +.emojiPickerAnswerMsg { + position: absolute; + bottom: 50px; + left: 20px; + z-index: 3; + width: fit-content; +} + +ngx-emoji { + display: flex; + align-items: center; +} + +app-small-btn { + display: flex; + align-items: top; + justify-content: center; + margin: 6px; +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .emoji { + width: 36px; + height: 24px; + padding: 5px 12px; + border-radius: 20px; + img { + height: 20px; + width: auto; + } + span { + font-size: 14px; + } + } + + ngx-emoji { + display: flex; + align-items: center; + height: 20px !important; + width: auto !important; + } +} diff --git a/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.spec.ts b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.spec.ts new file mode 100644 index 0000000..e610509 --- /dev/null +++ b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ReactionEmojisComponent } from './reaction-emojis.component'; + +describe('ReactionEmojisComponent', () => { + let component: ReactionEmojisComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ReactionEmojisComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ReactionEmojisComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.ts b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.ts new file mode 100644 index 0000000..5eb23a1 --- /dev/null +++ b/src/app/components/main-chat/single-chat/reaction-emojis/reaction-emojis.component.ts @@ -0,0 +1,225 @@ +import { + AfterViewInit, + Component, + ElementRef, + HostListener, + Input, + ViewChild, +} from '@angular/core'; +import { SmallBtnComponent } from '../../../../shared/components/small-btn/small-btn.component'; +import { CommonModule } from '@angular/common'; +import { + Chat, + ChatAnswers, + ChatReactions, +} from '../../../../interface/chat.interface'; +import { UserService } from '../../../../service/user.service'; +import { ChatService } from '../../../../service/chat.service'; +import { ChannleService } from '../../../../service/channle.service'; +import { EmojiPickerComponent } from '../../../../shared/components/emoji-picker/emoji-picker.component'; +import { EmojiComponent } from '@ctrl/ngx-emoji-mart/ngx-emoji'; +import { timeInterval } from 'rxjs'; +import { User } from '../../../../interface/user.interface'; +import { SharedService } from '../../../../service/shared.service'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-reaction-emojis', + standalone: true, + imports: [ + CommonModule, + SmallBtnComponent, + EmojiPickerComponent, + EmojiComponent, + TranslateModule, + ], + templateUrl: './reaction-emojis.component.html', + styleUrl: './reaction-emojis.component.scss', +}) +export class ReactionEmojisComponent { + @Input() user: User = {} as User; + @Input() chat: Chat | ChatAnswers = {} as Chat | ChatAnswers; + @Input() openOnSecondaryChat: boolean = false; + @Input() secondaryChatFirstMsg: boolean = false; + @Input() viewWidth: number = 0; + + reactionDialogId: string = ''; + reactionDialogLeft = 0; + isEmojiPickerVisible: boolean = false; + emojiSectionWidth: number = 0; + dialogX: number = 0; + dialogY: number = 0; + + constructor( + private elementRef: ElementRef, + public userService: UserService, + private chatService: ChatService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD_MOBILE = this.sharedService.RESPONSIVE_THRESHOLD_MOBILE; + + /** + * Emits an emoji output event. + * @param {any} $event - The emoji event. + * @param {string} chatId - The ID of the chat. + */ + emojiOutputEmitter($event: any, chatId: string) { + if (!this.checkExistEmojiOnChat(chatId, $event)) { + let reaction: ChatReactions = { + chatId: chatId, + icon: $event, + userId: [this.userService.getCurrentUserId()], + }; + const { id, ...reactionWithoutId } = reaction; + this.chatService.createNewReaction(reactionWithoutId); + } + } + + /** + * Emits an event indicating the visibility of the emoji picker. + * @param {any} $event - The visibility event. + */ + emojiVisibleEmitter($event: any) { + this.isEmojiPickerVisible = $event; + } + + /** + * Opens a dialog for a reaction. + * @param {any} reactionId - The ID of the reaction. + * @param {MouseEvent} event - The mouse event triggering the dialog. + */ + openDialog(reactionId: any, event: MouseEvent) { + this.reactionDialogId = reactionId; + this.updateDialogPosition(event); + } + + /** + * Closes the currently opened dialog. + */ + closeDialog() { + this.reactionDialogId = ''; + } + + /** + * Updates the position of the dialog based on the mouse event. + * @param {MouseEvent} event - The mouse event triggering the update. + */ + updateDialogPosition(event: MouseEvent) { + const currentTarget = event.currentTarget as HTMLElement; + if (currentTarget) { + const rect = currentTarget.getBoundingClientRect(); + this.dialogX = event.clientX - 200; + this.dialogY = event.clientY + 10; + } + } + + /** + * Checks if a given emoji exists on a chat. + * @param {string} chatId - The ID of the chat. + * @param {string} icon - The icon to check. + * @returns {boolean} True if the emoji exists, otherwise false. + */ + checkExistEmojiOnChat(chatId: string, icon: string) { + return this.getReaction(chatId).length > 0 && + this.getReactionIcon(chatId, icon).length > 0 + ? true + : false; + } + + /** + * Finds the index of an element in an array. + * @param {any[]} array - The array to search in. + * @param {any} element - The element to find the index of. + * @returns {number} The index of the element in the array. + */ + indexOfArray(array: any[], element: any): number { + return array.indexOf(element); + } + + /** + * Retrieves all reactions for a given chat. + * @param {string} chatId - The ID of the chat. + * @returns {ChatReactions[]} All reactions for the chat. + */ + getReaction(chatId: string) { + return this.chatService.allChatReactions.filter( + (reaction) => reaction.chatId === chatId + ); + } + + /** + * Retrieves reactions with a specific icon for a given chat. + * @param {string} chatId - The ID of the chat. + * @param {string} icon - The icon to filter by. + * @returns {ChatReactions[]} Reactions with the specified icon for the chat. + */ + getReactionIcon(chatId: string, icon: string) { + const chat = this.getReaction(chatId); + return chat.filter((reaction) => reaction.icon == icon); + } + + /** + * Retrieves the reaction document ID for a given chat. + * @param {string} chatId - The ID of the chat. + * @returns {ChatReactions[]} The reaction document ID for the chat. + */ + getReactionDocId(chatId: string) { + return this.chatService.allChatReactions.filter( + (reaction) => reaction.id === chatId + ); + } + + /** + * Counts the number of reaction document IDs for a given chat. + * @param {string} chatId - The ID of the chat. + * @returns {number} The count of reaction document IDs for the chat. + */ + countReactionDocId(chatId: string) { + let count = 0; + this.chatService.allChatReactions.forEach((reaction) => { + if (reaction.id === chatId) { + count++; + } + }); + return count; + } + + /** + * Retrieves user information based on user ID. + * @param {string} userId - The ID of the user. + * @returns {User[]} User information for the given user ID. + */ + getUserId(userId: string) { + const filteredUser = this.userService + .getUsers() + .filter((user) => user.id == userId); + return filteredUser; + } + + /** + * Toggles the presence of a user's reaction to a chat. + * @param {string} reactionID - The ID of the reaction. + */ + toggleEmoji(reactionID: string) { + const userIds = this.getReactionDocId(reactionID)[0].userId; + if (userIds.includes(this.userService.getCurrentUserId())) { + userIds.splice(userIds.indexOf(this.userService.getCurrentUserId()), 1); + if (userIds.length == 0) { + this.chatService.deleteData(reactionID, 'reactions'); + } else { + this.chatService.updateReaction(reactionID, userIds); + } + } else { + userIds.push(this.userService.getCurrentUserId()); + this.chatService.updateReaction(reactionID, userIds); + } + } + + /** + * Toggles the visibility of the emoji picker. + */ + toggleEmojiPicker() { + this.isEmojiPickerVisible = !this.isEmojiPickerVisible; + } +} diff --git a/src/app/components/main-chat/single-chat/single-chat.component.html b/src/app/components/main-chat/single-chat/single-chat.component.html new file mode 100644 index 0000000..0b6fec5 --- /dev/null +++ b/src/app/components/main-chat/single-chat/single-chat.component.html @@ -0,0 +1,147 @@ +
+ @if (firstLoadOptionMenu) { + + > + } +
+
+ +
+ @if (!isMsgEditFormOpen) { +
+
+ {{ user.firstName }} {{ user.lastName }} + + @if(openOnSecondaryChat) { + {{ convertTimestampDate(chat.publishedTimestamp) }} } + {{ convertTimestampHour(chat.publishedTimestamp) }} +
+
+
+ {{ chat.message }} + @if (chat.edited) { + {{ "single-chat.edit" | translate }} + } +
+ +
+ @if (!isPrivatChannel) { +
+ @if (chatService.getChatAnswers(chat.id).length > 0 && showAnswer) { + @if(chatService.getChatAnswers(chat.id).length == 1) { +

+ {{ displayCountChatAnswer() }} + {{ "single-chat.answer2" | translate }} +

+ {{ "single-chat.answer3" | translate }} + {{ displayLastChatAnswer() }} + } @else { +

+ {{ displayCountChatAnswer() }} + {{ "single-chat.answer" | translate }} +

+ {{ "single-chat.answer3" | translate }} + {{ displayLastChatAnswer() }} + } } @else if (showAnswer) { +

+ {{ "single-chat.answer4" | translate }} +

+ } +
+ } @else { +
+ } + +
+ } @else { +
+ +
+ } +
+
diff --git a/src/app/components/main-chat/single-chat/single-chat.component.scss b/src/app/components/main-chat/single-chat/single-chat.component.scss new file mode 100644 index 0000000..7b82964 --- /dev/null +++ b/src/app/components/main-chat/single-chat/single-chat.component.scss @@ -0,0 +1,216 @@ +@import "../../../../styles.scss"; + +section { + display: flex; + justify-content: flex-start; + padding: 32px 48px; + position: relative; + &:hover { + background-color: #edeefe; + .userContent { + .content { + background-color: #fff; + } + } + } +} + +.chat { + display: flex; + flex-direction: column; +} + +.menuRightSide { + position: absolute; + top: -24px; + right: 12px; + z-index: 2; +} + +.menuLeftSide { + position: absolute; + top: -24px; + left: 12px; + z-index: 2; +} + +.chatBox { + display: flex; + width: 100%; + max-width: 100%; +} + +.userAvatar { + img { + width: 70px; + height: 70px; + border-radius: 100%; + } +} + +.chat { + .name { + display: flex; + align-items: center; + font-size: 18px; + font-weight: 700; + span { + font-size: 14px; + font-weight: 400; + } + } + + .content { + max-width: 100%; + overflow-x: auto; + margin-top: 6px; + padding: 12px; + font-size: 18px; + font-weight: 400; + border-top-right-radius: 24px; + border-bottom-left-radius: 24px; + border-bottom-right-radius: 24px; + background-color: #eceefe; + .msg { + position: relative; + width: fit-content; + span { + font-size: 12px; + font-style: italic; + } + } + app-attachments  { + height: 200px; + } + } +} + +.content-mirror { + color: #fff; + border-top-left-radius: 24px; + border-top-right-radius: 0 !important; + background-color: #797ef3 !important; +} + +.answers { + display: flex; + align-items: center; + margin: 12px 0 6px 0; + p { + margin-right: 2px; + font-size: 18px; + font-weight: 400; + color: #535af1; + cursor: pointer; + &:hover { + margin-right: 0; + font-weight: 700; + color: #444df2; + } + } + span { + padding-left: 12px; + font-size: 14px; + font-weight: 400; + } +} + +.spacer { + margin: 9px; +} + +.editForm { + width: 100%; + border-radius: 20px; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, 0.2); +} + +/*------------- ANIMATION -------------*/ + +.animation-coming-in-left { + animation: coming-in-left 125ms ease-in-out forwards; +} + +.animation-coming-in-right { + animation: coming-in-right 125ms ease-in-out forwards; +} + +.animation-coming-out-left { + animation: coming-out-left 125ms ease-in-out forwards; +} +.animation-coming-out-right { + animation: coming-out-right 125ms ease-in-out forwards; +} + +@keyframes coming-in-left { + 0% { + opacity: 0; + transform: translateX(-12px); + } + 100% { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes coming-out-left { + 0% { + opacity: 1; + transform: translateX(0); + } + 100% { + opacity: 0; + transform: translateX(-12px); + } +} + +@keyframes coming-in-right { + 0% { + opacity: 0; + transform: translateX(12px); + } + 100% { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes coming-out-right { + 0% { + opacity: 1; + transform: translateX(0); + } + 100% { + opacity: 0; + transform: translateX(12px); + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + section { + padding: 24px 12px; + } + + .userAvatar { + img { + width: 50px; + height: 50px; + } + } + + .content { + font-size: 17px; + } + + .answers { + p { + font-size: 14px; + } + span { + font-size: 12px; + } + } +} diff --git a/src/app/components/main-chat/single-chat/single-chat.component.spec.ts b/src/app/components/main-chat/single-chat/single-chat.component.spec.ts new file mode 100644 index 0000000..196e52a --- /dev/null +++ b/src/app/components/main-chat/single-chat/single-chat.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SingleChatComponent } from './single-chat.component'; + +describe('SingleChatComponent', () => { + let component: SingleChatComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SingleChatComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SingleChatComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-chat/single-chat/single-chat.component.ts b/src/app/components/main-chat/single-chat/single-chat.component.ts new file mode 100644 index 0000000..f1960e8 --- /dev/null +++ b/src/app/components/main-chat/single-chat/single-chat.component.ts @@ -0,0 +1,176 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { User } from '../../../interface/user.interface'; +import { Chat, ChatAnswers } from '../../../interface/chat.interface'; +import { ChatContentComponent } from '../chat-content/chat-content.component'; +import { CommonModule, NgSwitchCase } from '@angular/common'; +import { ChatService } from '../../../service/chat.service'; +import { DownloadFilesService } from '../../../service/download-files.service'; +import { NgxExtendedPdfViewerModule } from 'ngx-extended-pdf-viewer'; +import { OptionsMenuComponent } from './options-menu/options-menu.component'; +import { AttachmentsComponent } from './attachments/attachments.component'; +import { ChatMsgBoxComponent } from '../chat-msg-box/chat-msg-box.component'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { FormsModule, NgForm } from '@angular/forms'; +import { PickerComponent } from '@ctrl/ngx-emoji-mart'; +import { EditMsgComponent } from './edit-msg/edit-msg.component'; +import { ReactionEmojisComponent } from './reaction-emojis/reaction-emojis.component'; +import { UserService } from '../../../service/user.service'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-single-chat', + standalone: true, + imports: [ + ChatContentComponent, + CommonModule, + FormsModule, + NgSwitchCase, + NgxExtendedPdfViewerModule, + OptionsMenuComponent, + AttachmentsComponent, + ChatMsgBoxComponent, + SmallBtnComponent, + PickerComponent, + EditMsgComponent, + ReactionEmojisComponent, + TranslateModule, + ], + templateUrl: './single-chat.component.html', + styleUrl: './single-chat.component.scss', +}) +export class SingleChatComponent { + @Input() user: User = {} as User; + @Input() chat: Chat | ChatAnswers = {} as Chat | ChatAnswers; + @Input() index: number = 0; + @Input() currentChat: string = ''; + @Input() isPrivatChannel: boolean = false; + @Input() showAnswer: boolean = false; + @Input() openOnSecondaryChat: boolean = false; + @Input() secondaryChatFirstMsg: boolean = false; + @Input() viewWidth: number = 0; + + trustedUrl: string = ''; + isOptionMenuVisible: boolean = false; + isMsgEditFormOpen: boolean = false; + firstLoadOptionMenu: boolean = false; + + constructor( + public chatService: ChatService, + public channelService: ChatService, + public userService: UserService, + public downloadFilesService: DownloadFilesService + ) {} + + /** + * Emits a signal to edit a message. + * @param {boolean} variable - The value indicating whether the message edit form should be open or not. + */ + editMsgEmitter(variable: boolean) { + this.isMsgEditFormOpen = variable; + } + + /** + * Emits a signal to close the message edit form and hide the option menu. + * @param {boolean} value - The value indicating whether the message edit form should be closed. + */ + closeEditMsgEmitter(value: boolean) { + this.isMsgEditFormOpen = value; + this.hideOptionMenu(); + } + + /** + * Shows the option menu. + */ + showOptionMenu() { + this.isOptionMenuVisible = true; + this.firstLoadOptionMenu = true; + } + + /** + * Hides the option menu. + */ + hideOptionMenu() { + this.isOptionMenuVisible = false; + this.firstLoadOptionMenu = true; + } + + /** + * Displays the count of chat answers. + * @returns {number} The count of chat answers. + */ + displayCountChatAnswer() { + return this.chatService.getChatAnswers(this.chat.id).length; + } + + /** + * Displays the timestamp of the last chat answer in a formatted time. + * @returns {string|null} The formatted time of the last chat answer. + */ + displayLastChatAnswer() { + const getChatAnswers = this.chatService.getChatAnswers(this.chat.id); + const lastChatAnswer = getChatAnswers[getChatAnswers.length - 1]; + if (lastChatAnswer) { + return this.convertTimestampHour(lastChatAnswer.publishedTimestamp); + } + return null; + } + + /** + * Converts a timestamp to a formatted time string. + * @param {number} timestamp - The timestamp to convert. + * @returns {string} The formatted time string. + */ + convertTimestampHour(timestamp: number) { + const date = new Date(timestamp * 1000); + let hour = date.getHours(); + const minute = ('0' + date.getMinutes()).slice(-2); + const period = hour >= 12 ? 'PM' : 'AM'; + hour = hour % 12 || 12; + + let hourWithNull = ('0' + hour).slice(-2); + + const formattedTime = `${hourWithNull}:${minute} ${period}`; + return formattedTime; + } + + /** + * Converts a timestamp to a formatted date string. + * @param {number} timestamp - The timestamp to convert. + * @returns {string} The formatted date string. + */ + convertTimestampDate(timestamp: number) { + const currentDate = new Date(); + const inputDate = new Date(timestamp * 1000); + const months = [ + 'Jan.', + 'Feb.', + 'Mar.', + 'Apr.', + 'May.', + 'Jun.', + 'Jul.', + 'Aug.', + 'Sep.', + 'Oct.', + 'Nov.', + 'Dec.', + ]; + + const dayNumber = inputDate.getDate(); + const month = months[inputDate.getMonth()]; + + if (inputDate.toDateString() === currentDate.toDateString()) { + return `Today`; + } else { + return `${dayNumber} ${month}`; + } + } + + /** + * Opens a secondary chat. + * @param {string} chatId - The ID of the secondary chat to open. + */ + openSecondaryChat(chatId: string) { + this.chatService.toggleSecondaryChat(chatId); + } +} diff --git a/src/app/components/main-login/choose-avatar/choose-avatar.component.html b/src/app/components/main-login/choose-avatar/choose-avatar.component.html new file mode 100644 index 0000000..d096f2c --- /dev/null +++ b/src/app/components/main-login/choose-avatar/choose-avatar.component.html @@ -0,0 +1,57 @@ +
+ +
+
+
+ + +
+ {{ 'chooseAvatar.header' | translate }} +
+ +
+ Avatar + {{ loginService.firstName }} {{ loginService.lastName }} +
+
+ +
+
+
{{ 'chooseAvatar.avatarInfo' | translate }}
+
+ +
+
+ +
+
{{ 'chooseAvatar.ownAvatar' | translate }}
+
+ +
+
+ +
+ +
+
+ +
diff --git a/src/app/components/main-login/choose-avatar/choose-avatar.component.scss b/src/app/components/main-login/choose-avatar/choose-avatar.component.scss new file mode 100644 index 0000000..ac8a4ac --- /dev/null +++ b/src/app/components/main-login/choose-avatar/choose-avatar.component.scss @@ -0,0 +1,146 @@ +@import "../../../shared/components/login/mixins/mixin.scss"; +* { + font-family: Nunito; +} + +.avatarSektion { + @include SektionBody; +} +.avatarContainer { + @include Card; +} +.avatarTop { + @include topText; + > span { + width: 90%; + padding-right: 48px; + } +} +.viewAvatarContainer { + display: flex; + flex-direction: column; + text-align: center; + align-items: center; + gap: 24px; + > img { + height: 168px; + width: 168px; + border-radius: 100%; + object-fit: cover; + } + > span { + font-size: 32px; + font-weight: 700; + } +} +.chooseAvatarContainer { + gap: 16px; + display: flex; + flex-direction: column; + margin-bottom: 8px; + > div { + display: flex; + gap: 4px; + > span { + font-size: 20px; + font-weight: 400; + } + > img { + height: 72px; + border-radius: 100%; + border: 4px solid #ffff; + cursor: pointer; + &:hover { + border: 4px solid #cacad6; + } + } + } +} +.ownAvatarContainer { + display: flex; + gap: 32px; + margin-right: 67px; + > div { + display: flex; + align-items: center; + font-size: 20px; + font-weight: 400; + } +} +.BtnUpload { + background-color: #ffff; + color: #444df2; + border: 1px solid #444df2; + cursor: pointer; + &:hover { + background-color: #444df2; + color: #ffff; + } +} + +.avatarBottom { + display: flex; + justify-content: end; + + width: 100%; +} + +button { + @include buttonGrey; + cursor: pointer; +} +.hoverBtn { + &:hover { + background-color: #676eec; + } +} +@media (max-width: 570px) { + .avatarTop { + margin-bottom: 0; + + > span { + font-size: 32px; + white-space: nowrap; + } + } + .viewAvatarContainer { + > img { + height: 148px; + width: 148px; + } + } + .chooseAvatarContainer { + width: 100%; + } + .mobileImgContainer { + overflow: auto; + } + .ownAvatarContainer { + margin-right: 0; + gap: 16px; + flex-direction: column; + } + .avatarBottom { + margin-top: 8px; + } + .BtnUpload { + &:hover { + background-color: #ffff; + color: #444df2; + } + } + .hoverBtn { + background-color: #676eec; + } + @media (max-width: 380px) { + .avatarContainer { + max-width: 306px; + } + .avatarTop { + width: 95%; + > span { + font-size: 24px; + } + } + } +} diff --git a/src/app/components/main-login/choose-avatar/choose-avatar.component.spec.ts b/src/app/components/main-login/choose-avatar/choose-avatar.component.spec.ts new file mode 100644 index 0000000..7f95706 --- /dev/null +++ b/src/app/components/main-login/choose-avatar/choose-avatar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChooseAvatarComponent } from './choose-avatar.component'; + +describe('ChooseAvatarComponent', () => { + let component: ChooseAvatarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ChooseAvatarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ChooseAvatarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-login/choose-avatar/choose-avatar.component.ts b/src/app/components/main-login/choose-avatar/choose-avatar.component.ts new file mode 100644 index 0000000..d73b0a9 --- /dev/null +++ b/src/app/components/main-login/choose-avatar/choose-avatar.component.ts @@ -0,0 +1,96 @@ +import { Component, inject } from '@angular/core'; +import { FooterComponent } from '../../../shared/components/login/footer/footer.component'; +import { RouterModule } from '@angular/router'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { getStorage, ref, uploadBytes, getDownloadURL } from 'firebase/storage'; +import { Firestore } from '@angular/fire/firestore'; +import { CommonModule } from '@angular/common'; +import { loginService } from '../../../service/login.service'; +import { StartHeaderComponent } from '../../../shared/components/login/start-header/start-header.component'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-choose-avatar', + standalone: true, + templateUrl: './choose-avatar.component.html', + styleUrl: './choose-avatar.component.scss', + imports: [ + StartHeaderComponent, + FooterComponent, + RouterModule, + SmallBtnComponent, + CommonModule, + TranslateModule, + ], +}) +export class ChooseAvatarComponent { + avatarSrc: string = './assets/img/user-icons/guest.svg'; + firestore: Firestore = inject(Firestore); + selectedFile: File | null = null; + avatarImages: string[] = [ + './assets/img/user-icons/female-1.svg', + './assets/img/user-icons/female-2.svg', + './assets/img/user-icons/male-1.svg', + './assets/img/user-icons/male-2.svg', + './assets/img/user-icons/male-3.svg', + './assets/img/user-icons/male-4.svg', + ]; + + constructor(public loginService: loginService) {} + + /** + * Handles file selection changes and initiates the upload of the avatar. + * @param event The DOM event containing the file selection. + */ + onFileChange(event: Event) { + const inputElement = event.target as HTMLInputElement; + + if (inputElement.files && inputElement.files[0]) { + const file = inputElement.files[0]; + + if (!file.type.startsWith('image/')) { + console.error('Datei ist kein Bild.'); + return; + } + this.selectedFile = file; + const reader = new FileReader(); + reader.onload = (e: any) => { + this.avatarSrc = e.target.result; + }; + reader.readAsDataURL(file); + this.uploadFile(file); + } + } + + /** + * Uploads the selected file to Firebase Storage. + * @param file The file to be uploaded. + */ + uploadFile(file: File) { + const storage = getStorage(); + const storageRef = ref(storage, 'avatars/' + file.name); + uploadBytes(storageRef, file) + .then((snapshot) => { + getDownloadURL(ref(storage, 'avatars/' + file.name)) + .then((url) => { + this.avatarSrc = url; + this.loginService.getAvatarUrl(url); + }) + .catch((error) => + console.error('Fehler beim Abrufen der Download-URL:', error) + ); + }) + .catch((error) => { + console.error('Fehler beim Hochladen:', error); + }); + } + + /** + * Selects an avatar from the list of predefined avatars. + * @param index Index of the chosen avatar in the avatarImages list. + */ + chooseExistAvatar(index: number) { + this.avatarSrc = this.avatarImages[index]; + this.loginService.getAvatarUrl(this.avatarSrc); + } +} diff --git a/src/app/components/main-login/login/login.component.html b/src/app/components/main-login/login/login.component.html new file mode 100644 index 0000000..4476587 --- /dev/null +++ b/src/app/components/main-login/login/login.component.html @@ -0,0 +1,102 @@ +
+ +
+
+ {{ "login.header" | translate }} +
+
+ {{ "login.infoText" | translate }} +
+
+
+ + + @if (!emailField.valid && emailField.touched) { +

{{ "login.errorText" | translate }}

+ } +
+
+ + + Toggle visibility + @if (!passwordField.valid && passwordField.touched) { +

{{ "login.errorText2" | translate }}

+ } @if (loginService.errorMessage) { +

{{ loginService.errorMessage }}

+ } +
+ +
+ {{ + "login.midText" | translate + }} +
+ +
+
+ {{ "login.midSeperator" | translate }} +
+
+ +
+ + {{ "login.googleBtn" | translate }} +
+ +
+ + +
+
+
+
+
+ {{ "login.topText" | translate }} +
+ + {{ "login.topText2" | translate }} +
+
+
+ +
diff --git a/src/app/components/main-login/login/login.component.scss b/src/app/components/main-login/login/login.component.scss new file mode 100644 index 0000000..ec25642 --- /dev/null +++ b/src/app/components/main-login/login/login.component.scss @@ -0,0 +1,249 @@ +@import "../../../shared/components/login/mixins/mixin.scss"; +.startIntroScrollProtect { + overflow-x: hidden; + overflow-y: hidden; +} +.loginSektion { + @include SektionBody; +} +.loginContainer { + @include Card; +} +.loginTop { + @include topText; +} + +.loginBackImg { + cursor: pointer; +} +.loginInfoText { + @include InfoText; +} +.inputContainer { + position: relative; + margin-bottom: 32px; +} +.iconP { + position: absolute; + top: 18px; + left: 20px; +} +.inputField { + @include inputStyle; +} +.error { + @include errorStyle; +} +.contactForm { + width: 90%; +} +.passwordContainer { + text-align: center; + color: rgba(121, 126, 243, 1); + font-size: 18px; + margin-bottom: 32px; + margin-top: 40px; + > span { + font-family: Figtree, sans-serif, Nunito; + color: #797ef3; + &:hover { + cursor: pointer; + font-weight: 500; + background-color: #eceefe; + padding: 12px 16px 12px 16px; + border-radius: 100px; + color: #444df2; + } + } +} +.separatorContainer { + display: flex; + justify-content: center; + align-items: baseline; + gap: 10px; + font-size: 18px; + margin-bottom: 32px; + > div { + border: 1px solid #adb0d9; + width: 42%; + height: 0px; + display: flex; + justify-content: center; + } +} +.googleLogingContainer { + display: flex; + justify-content: center; + align-items: center; + gap: 10px; + border: 1px solid #ffff; + font-size: 18px; + outline: none; + width: 100%; + box-sizing: border-box; + background: #eceefe; + height: 60px; + border-radius: 100px; + color: rgba(121, 126, 243, 1); + &:hover { + font-weight: 700; + border: 1px solid #444df2; + color: #444df2; + cursor: pointer; + } +} + +.loginBottom { + display: flex; + justify-content: center; + margin-top: 32px; + gap: 30px; +} + +button { + @include buttonGrey; +} +.aktivButton { + @include aktivButtonBlue; +} +.aktivInput { + border: 1px solid#686868; +} +.guestButton { + padding: 12px 25px; + color: #444df2; + background-color: #ffff; + border: 1px solid #444df2; + outline: none; + box-sizing: border-box; + transition: 0.2s; + border-radius: 25px; + font-size: 18px; + font-weight: 600; + cursor: pointer; + &:hover { + background-color: #444df2; + color: #fff; + border: 1px solid #ffff; + } +} +.mobileRegisterContainer { + display: none; + > div { + display: flex; + flex-direction: column; + gap: 20px; + text-align: center; + > span { + font-weight: 400; + font-size: 18px; + } + } +} +.mobileCreateAccountContainer { + display: flex; + justify-content: end; +} +.mobileCreateAccoun { + font-family: Figtree, sans-serif, Nunito; + color: #797ef3; + cursor: pointer; + padding: 4px 12px 4px 12px; + border-radius: 100px; + border: 1px solid #eceefe; + font-weight: 400; + font-size: 18px; + &:hover { + font-weight: 500; + background-color: #eceefe; + color: #444df2; + border: 1px solid #444df2; + } +} +.passwordEye { + position: absolute; + top: 18px; + right: 25px; +} +@media (max-width: 570px) { + .loginTop { + margin-bottom: 0; + > span { + font-size: 32px; + } + } + .loginInfoText { + margin-bottom: 0; + > span { + font-size: 17px; + } + } + .loginContainer { + padding: 16px; + max-height: 552px; + padding-left: 18px; + padding-right: 18px; + gap: 12px; + max-width: 400px; + } + .contactForm { + width: 100%; + } + .inputContainer { + margin-bottom: 22px; + } + .inputField { + height: 52px; + font-size: 15px; + } + .iconP { + top: 15px; + } + .passwordContainer { + margin-bottom: 22px; + margin-top: 32px; + font-size: 17px; + } + .separatorContainer { + font-size: 17px; + margin-bottom: 22px; + } + .googleLogingContainer { + font-size: 17px; + height: 52px; + gap: 0; + margin-bottom: 22px; + > img { + height: 32px; + } + } + .loginBottom { + margin-top: 0px; + gap: 24px; + > button { + width: 118px; + height: 52px; + padding: 0; + } + } + .guestButton { + font-size: 17px; + white-space: nowrap; + } + .aktivButton { + font-size: 17px; + } + .mobileRegisterContainer { + display: flex; + background-color: #eceefe; + width: 100vw; + padding-top: 40px; + justify-content: center; + } +} + +@media (max-width: 380px) { + .loginContainer { + max-width: 306px; + } +} diff --git a/src/app/components/main-login/login/login.component.spec.ts b/src/app/components/main-login/login/login.component.spec.ts new file mode 100644 index 0000000..1e19e5d --- /dev/null +++ b/src/app/components/main-login/login/login.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [LoginComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-login/login/login.component.ts b/src/app/components/main-login/login/login.component.ts new file mode 100644 index 0000000..4ca05df --- /dev/null +++ b/src/app/components/main-login/login/login.component.ts @@ -0,0 +1,62 @@ +import { Component, ElementRef, Renderer2 } from '@angular/core'; +import { loginService } from '../../../service/login.service'; +import { FormsModule } from '@angular/forms'; +import { RouterLink } from '@angular/router'; +import { FooterComponent } from '../../../shared/components/login/footer/footer.component'; +import { CommonModule } from '@angular/common'; +import { StartHeaderComponent } from '../../../shared/components/login/start-header/start-header.component'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-login', + standalone: true, + templateUrl: './login.component.html', + styleUrl: './login.component.scss', + imports: [ + FormsModule, + CommonModule, + FooterComponent, + RouterLink, + StartHeaderComponent, + TranslateModule, + ], +}) +export class LoginComponent { + constructor( + public loginService: loginService, + private elRef: ElementRef, + private renderer: Renderer2 + ) {} + + /** + * Initializes the component and manages the removal of the 'startIntroScrollProtect' class from an element. + * On the first load, this class is removed after a delay of 4.5 seconds to manage initial UI transitions. + * On subsequent loads, the class is removed immediately, ensuring the UI remains consistent without delay. + * This behavior is controlled by the `isFirstLoad` property of the loginService. + */ + ngOnInit(): void { + const element = this.elRef.nativeElement.querySelector( + '.startIntroScrollProtect' + ); + + if (this.loginService.isFirstLoad) { + setTimeout(() => { + if (element) { + this.renderer.removeClass(element, 'startIntroScrollProtect'); + } + }, 4500); + + this.loginService.isFirstLoad = false; + } else if (element) { + this.renderer.removeClass(element, 'startIntroScrollProtect'); + } + } + + /** + * Handles form submission by triggering the login process through a login service. + * This method would typically be called when a user submits a form associated with logging in. + */ + onSubmit() { + this.loginService.login(); + } +} diff --git a/src/app/components/main-login/main-login.component.html b/src/app/components/main-login/main-login.component.html new file mode 100644 index 0000000..ab1b0b2 --- /dev/null +++ b/src/app/components/main-login/main-login.component.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/app/components/main-login/main-login.component.scss b/src/app/components/main-login/main-login.component.scss new file mode 100644 index 0000000..cba248c --- /dev/null +++ b/src/app/components/main-login/main-login.component.scss @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/app/components/main-login/main-login.component.spec.ts b/src/app/components/main-login/main-login.component.spec.ts new file mode 100644 index 0000000..d44a0b0 --- /dev/null +++ b/src/app/components/main-login/main-login.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MainLoginComponent } from './main-login.component'; + +describe('LoginComponent', () => { + let component: MainLoginComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MainLoginComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MainLoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-login/main-login.component.ts b/src/app/components/main-login/main-login.component.ts new file mode 100644 index 0000000..5da3630 --- /dev/null +++ b/src/app/components/main-login/main-login.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { RegisterComponent } from "./register/register.component"; +import { ChooseAvatarComponent } from "./choose-avatar/choose-avatar.component"; +import { LoginComponent } from "./login/login.component"; +import { PasswordForgetComponent } from "./password-forget/password-forget.component"; +import { PasswordResetComponent } from "./password-reset/password-reset.component"; +import { loginService } from '../../service/login.service'; +import { CommonModule } from '@angular/common'; +import { RouterLink } from '@angular/router'; + +@Component({ + selector: 'app-main-login', + standalone: true, + templateUrl: './main-login.component.html', + styleUrl: './main-login.component.scss', + imports: [CommonModule,RegisterComponent, ChooseAvatarComponent, LoginComponent, PasswordForgetComponent, PasswordResetComponent,RouterLink] +}) +export class MainLoginComponent { + +} diff --git a/src/app/components/main-login/password-forget/password-forget.component.html b/src/app/components/main-login/password-forget/password-forget.component.html new file mode 100644 index 0000000..7015664 --- /dev/null +++ b/src/app/components/main-login/password-forget/password-forget.component.html @@ -0,0 +1,61 @@ +
+ +
+
+
+ + +
+ {{ 'passwordForget.header' | translate }} +
+
+ {{ 'passwordForget.infoText' | translate }} +
+
+
+ + + @if (!emailField.valid && emailField.touched) { +

{{ 'login.errorText' | translate }}

+ } +
+
+ + {{ 'passwordForget.infoTextBottom' | translate }} +
+
+ +
+
+
+
+ +
+ +
diff --git a/src/app/components/main-login/password-forget/password-forget.component.scss b/src/app/components/main-login/password-forget/password-forget.component.scss new file mode 100644 index 0000000..8a6dec6 --- /dev/null +++ b/src/app/components/main-login/password-forget/password-forget.component.scss @@ -0,0 +1,170 @@ +@import "../../../shared/components/login/mixins/mixin.scss"; + +.passwordSektion { + @include SektionBody; +} + +.passwordContainer { + max-width: 606px; + width: 100%; + background-color: #fff; + border-radius: 30px; + box-sizing: border-box; + padding: 32px; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + gap: 24px; + max-height: 470px; + height: 100%; +} + +.passwordTop { + @include topText; + > span { + width: 90%; + padding-right: 48px; + } +} + +.passwordBackImg { + cursor: pointer; +} + +.passwordInfoText { + @include InfoText; +} + +.inputContainer { + position: relative; + margin-bottom: 48px; +} + +.iconP { + position: absolute; + top: 18px; + left: 20px; +} + +.inputField { + @include inputStyle; +} + +.error { + @include errorStyle; +} + +.contactForm { + width: 90%; +} + +.passwordBottom { + display: flex; + justify-content: end; + margin-top: 32px; + gap: 30px; +} + +button { + @include buttonGrey; +} + +.aktivButton { + @include aktivButtonBlue; +} + +.aktivInput { + border: 1px solid#686868; +} + +.bottomInfoText { + display: flex; + justify-content: center; + > span { + width: 380px; + text-align: center; + font-size: 20px; + font-weight: 400; + color: #686868; + } +} + +.sendBtn { + display: none; + position: absolute; + right: 0; + bottom: 11%; + animation: slideInOut 4s ease-in-out forwards; + > img { + height: 118px; + } +} + +@keyframes slideInOut { + 0%, + 100% { + opacity: 0; + transform: translateX(100%); + } + 10%, + 90% { + opacity: 1; + transform: translateX(0); + } + 90% { + transform: translateY(0); + } + 100% { + transform: translateY(100%); + } +} +@media (max-width: 570px) { + .passwordTop { + margin-bottom: 0; + + > span { + font-size: 26px; + } + } + .passwordInfoText { + > span { + font-size: 18px; + } + } + .inputField { + padding-left: 40px; + font-size: 17px; + } + .iconP { + left: 12px; + } + .bottomInfoText { + > span { + font-size: 18px; + } + } +} +@media (max-width: 420px) { + .passwordTop { + > span { + font-size: 24px; + } + } + .contactForm { + min-width: 262px; + } + .passwordContainer { + gap: 16px; + max-width: 306px; + } + .inputField { + font-size: 15px; + } + .bottomInfoText { + margin-bottom: 24px; + } + .inputContainer { + margin-bottom: 24px; + } +} diff --git a/src/app/components/main-login/password-forget/password-forget.component.spec.ts b/src/app/components/main-login/password-forget/password-forget.component.spec.ts new file mode 100644 index 0000000..7d8b114 --- /dev/null +++ b/src/app/components/main-login/password-forget/password-forget.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PasswordForgetComponent } from './password-forget.component'; + +describe('PasswordForgetComponent', () => { + let component: PasswordForgetComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PasswordForgetComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PasswordForgetComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-login/password-forget/password-forget.component.ts b/src/app/components/main-login/password-forget/password-forget.component.ts new file mode 100644 index 0000000..d218350 --- /dev/null +++ b/src/app/components/main-login/password-forget/password-forget.component.ts @@ -0,0 +1,77 @@ +import { Component, inject } from '@angular/core'; +import { FooterComponent } from '../../../shared/components/login/footer/footer.component'; +import { FormsModule, NgForm } from '@angular/forms'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { getAuth, sendPasswordResetEmail } from 'firebase/auth'; +import { Firestore } from '@angular/fire/firestore'; +import { Router } from '@angular/router'; +import { StartHeaderComponent } from '../../../shared/components/login/start-header/start-header.component'; +import { TranslateModule} from '@ngx-translate/core'; + +@Component({ + selector: 'app-password-forget', + standalone: true, + templateUrl: './password-forget.component.html', + styleUrl: './password-forget.component.scss', + imports: [ + FormsModule, + CommonModule, + FooterComponent, + RouterModule, + SmallBtnComponent, + StartHeaderComponent, + TranslateModule + ], +}) + +export class PasswordForgetComponent { + email: string = ''; + emailSentBtn = false; + firestore: Firestore = inject(Firestore); + constructor(private router: Router) {} + + + /** + * Initiates a password reset process for the user. + * Sends a password reset email to the user's registered email address. + * + * @param ngForm The form data from the Angular form, used to manage form state. + */ + passwordReset(ngForm: NgForm) { + const auth = getAuth(); + sendPasswordResetEmail(auth, this.email) + .then(() => { + ngForm.resetForm(ngForm); + this.router.navigate(['/login']); + }) + .catch((error) => { + const errorCode = error.code; + const errorMessage = error.message; + }); + } + + + /** + * Handles the form submission, invoking the password reset function and then sending a notification email. + * + * @param ngForm The form instance containing user input. + */ + onSubmit(ngForm: NgForm) { + this.passwordReset(ngForm); + this.sendEmail(); + } + + + /** + * Simulates sending an email by toggling a button state to show feedback to the user. + * After a set timeout, resets the button state. + */ + sendEmail() { + this.emailSentBtn = true; + setTimeout(() => { + this.emailSentBtn = false; + }, 6000); + } +} diff --git a/src/app/components/main-login/password-reset/password-reset.component.html b/src/app/components/main-login/password-reset/password-reset.component.html new file mode 100644 index 0000000..238e083 --- /dev/null +++ b/src/app/components/main-login/password-reset/password-reset.component.html @@ -0,0 +1,83 @@ +
+ +
+
+
+ + +
+ {{ 'passwordReset.header' | translate }} +
+ +
+
+ + + @if (!passwordField.valid && passwordField.touched) { +

+ {{ 'passwordReset.errorText' | translate }} +

+ } +
+
+ + + +

+ {{ 'passwordReset.errorText2' | translate }} +

+
+
+ +
+
+
+ +
diff --git a/src/app/components/main-login/password-reset/password-reset.component.scss b/src/app/components/main-login/password-reset/password-reset.component.scss new file mode 100644 index 0000000..d3d3657 --- /dev/null +++ b/src/app/components/main-login/password-reset/password-reset.component.scss @@ -0,0 +1,111 @@ +@import "../../../shared/components/login/mixins/mixin.scss"; +.passwordSektion { + @include SektionBody; +} +.passwordContainer { + max-width: 606px; + width: 100%; + background-color: #fff; + border-radius: 30px; + box-sizing: border-box; + padding: 32px; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + gap: 24px; + max-height: 470px; + height: 100%; +} +.passwordTop { + @include topText; + > span { + width: 90%; + padding-right: 48px; + } +} + +.passwordBackImg { + cursor: pointer; +} + +.inputContainer { + position: relative; + margin-bottom: 48px; +} +.iconP { + position: absolute; + top: 18px; + left: 20px; +} +.inputField { + @include inputStyle; +} +.error { + @include errorStyle; +} +.contactForm { + width: 90%; +} + +.passwordBottom { + display: flex; + justify-content: end; + margin-top: 32px; + gap: 30px; +} + +button { + @include buttonGrey; +} +.aktivButton { + @include aktivButtonBlue; +} +.aktivInput { + border: 1px solid#686868; +} +@media (max-width: 570px) { + .passwordTop { + > span { + font-size: 38px; + } + } +} +@media (max-width: 570px) { + .passwordTop { + margin-bottom: 48px; + + > span { + font-size: 34px; + } + } + .inputField { + padding-left: 40px; + font-size: 17px; + } + .iconP { + left: 12px; + } +} +@media (max-width: 420px) { + .passwordTop { + > span { + font-size: 28px; + } + } + .contactForm { + min-width: 262px; + } + .passwordContainer { + gap: 16px; + } + .inputField { + font-size: 15px; + } + .bottomInfoText { + margin-bottom: 24px; + } + .inputContainer { + margin-bottom: 48px; + } +} diff --git a/src/app/components/main-login/password-reset/password-reset.component.spec.ts b/src/app/components/main-login/password-reset/password-reset.component.spec.ts new file mode 100644 index 0000000..8aaad64 --- /dev/null +++ b/src/app/components/main-login/password-reset/password-reset.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PasswordResetComponent } from './password-reset.component'; + +describe('PasswordResetComponent', () => { + let component: PasswordResetComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PasswordResetComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PasswordResetComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-login/password-reset/password-reset.component.ts b/src/app/components/main-login/password-reset/password-reset.component.ts new file mode 100644 index 0000000..71b0999 --- /dev/null +++ b/src/app/components/main-login/password-reset/password-reset.component.ts @@ -0,0 +1,95 @@ +import { Component, inject } from '@angular/core'; +import { FooterComponent } from '../../../shared/components/login/footer/footer.component'; +import { FormsModule, NgForm } from '@angular/forms'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; +import { StartHeaderComponent } from '../../../shared/components/login/start-header/start-header.component'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { Router, ActivatedRoute } from '@angular/router'; +import { getAuth } from 'firebase/auth'; +import { confirmPasswordReset } from 'firebase/auth'; +import { Subscription } from 'rxjs'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-password-reset', + standalone: true, + imports: [ + FormsModule, + CommonModule, + StartHeaderComponent, + FooterComponent, + RouterModule, + SmallBtnComponent, + TranslateModule + ], + templateUrl: './password-reset.component.html', + styleUrl: './password-reset.component.scss', +}) +export class PasswordResetComponent { + password: string = ''; + passwordRepeat: string = ''; + oobCode: string = ''; + private queryParamsSubscription: Subscription = new Subscription(); + + constructor( + private route: ActivatedRoute, + private router: Router, + ) {} + + +/** + * Initializes the component by subscribing to query parameters. + */ + ngOnInit(): void { + this.queryParamsSubscription = this.route.queryParams.subscribe( + (params) => { + this.oobCode = params['oobCode']; + } + ); + } + + +/** + * Handles the submission of the password reset form. + * @param ngForm The form data of the password reset form. + */ + onSubmit(ngForm: NgForm): void { + this.resetPassword(ngForm); + } + + +/** + * Performs the password reset operation using Firebase Authentication. + * @param ngForm The form data of the password reset form. + */ + resetPassword(ngForm: NgForm): void { + const auth = getAuth(); + const newPassword = this.passwordRepeat; + confirmPasswordReset(auth, this.oobCode, newPassword) + .then(() => { + ngForm.resetForm(); + this.router.navigate(['/login']); + }) + .catch((error) => { + console.error('Fehler beim Zurücksetzen des Passworts:', error); + }); + } + + + /** + * Cleans up the component by unsubscribing from the query parameters subscription. + */ + ngOnDestroy(): void { + this.queryParamsSubscription.unsubscribe(); + } + + + /** + * Checks if the entered passwords match. + * @returns true if the password and repeated password are the same. + */ + passwordsMatch(): boolean { + return this.password === this.passwordRepeat; + } +} diff --git a/src/app/components/main-login/register/register.component.html b/src/app/components/main-login/register/register.component.html new file mode 100644 index 0000000..36b8406 --- /dev/null +++ b/src/app/components/main-login/register/register.component.html @@ -0,0 +1,117 @@ +
+ +
+
+
+ + +
+ {{ 'createAccount.header' | translate }} +
+
+ {{ 'createAccount.infoText' | translate }} +
+
+
+ + + @if (!nameField.valid && nameField.touched) { +

{{ 'createAccount.errorText' | translate }}

+ } +
+
+ + + @if (!emailField.valid && emailField.touched) { +

{{ 'createAccount.errorText2' | translate }}

+ } +
+
+ + + Toggle visibility + @if (!passwordField.valid && passwordField.touched) { +

+ {{ 'createAccount.errorText3' | translate }} +

+ } +
+ +
+
+ +
+ {{ 'createAccount.midText' | translate }} + {{ 'createAccount.midText2' | translate }} {{ 'createAccount.midText3' | translate }} +
+
+ +
+
+
+ +
diff --git a/src/app/components/main-login/register/register.component.scss b/src/app/components/main-login/register/register.component.scss new file mode 100644 index 0000000..1bec886 --- /dev/null +++ b/src/app/components/main-login/register/register.component.scss @@ -0,0 +1,135 @@ +@import "../../../shared/components/login/mixins/mixin.scss"; +.registerSektion { + @include SektionBody; +} +.registerContainer { + @include Card; + gap: 42px !important; +} +.registerTop { + @include topText; + > span { + width: 90%; + padding-right: 48px; + } +} + +.registerBackImg { + cursor: pointer; +} +.registerInfoText { + @include InfoText; +} +.inputContainer { + position: relative; + margin-bottom: 32px; +} +.iconP { + position: absolute; + top: 16px; + left: 20px; +} +.inputField { + @include inputStyle; +} + +.error { + @include errorStyle; +} +.contactForm { + width: 90%; +} +.checkBox { + display: flex; + align-items: center; + gap: 8px; + > div { + cursor: pointer; + } +} +.registerBottom { + display: flex; + justify-content: end; + margin-top: 32px; +} + +button { + @include buttonGrey; +} +.aktivButton { + @include aktivButtonBlue; +} +.aktivInput { + border: 1px solid#686868; +} + +.fontColor { + color: #797ef3; + cursor: pointer; + &:hover { + font-weight: 500; + background-color: #eceefe; + padding: 2px 2px 2px 5px; + border-radius: 100px; + color: #444df2; + } +} + +.passwordEye { + position: absolute; + top: 18px; + right: 25px; +} + +@media (max-width: 570px) { + .registerTop { + margin-bottom: 0; + > span { + font-size: 32px; + } + } + .registerInfoText { + margin-bottom: 0; + > span { + font-size: 17px; + } + } + .registerContainer { + padding: 16px; + max-height: 552px; + padding-left: 18px; + padding-right: 18px; + gap: 12px; + max-width: 400px; + } + .contactForm { + width: 100%; + } + .inputContainer { + margin-bottom: 22px; + } + .inputField { + height: 52px; + font-size: 15px; + } + .iconP { + top: 15px; + } + .registerBottom { + margin-top: 26px; + gap: 24px; + } + .guestButton { + font-size: 17px; + white-space: nowrap; + } + .aktivButton { + font-size: 17px; + } +} +@media (max-width: 380px) { + .registerContainer { + max-width: 306px; + gap: 12px !important; + } +} diff --git a/src/app/components/main-login/register/register.component.spec.ts b/src/app/components/main-login/register/register.component.spec.ts new file mode 100644 index 0000000..3a5dfc8 --- /dev/null +++ b/src/app/components/main-login/register/register.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RegisterComponent } from './register.component'; + +describe('RegisterComponent', () => { + let component: RegisterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RegisterComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(RegisterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main-login/register/register.component.ts b/src/app/components/main-login/register/register.component.ts new file mode 100644 index 0000000..aec7de3 --- /dev/null +++ b/src/app/components/main-login/register/register.component.ts @@ -0,0 +1,95 @@ +import { Component, inject } from '@angular/core'; +import { FormsModule, NgForm } from '@angular/forms'; +import { Firestore } from '@angular/fire/firestore'; +import { CommonModule } from '@angular/common'; +import { RouterLink, Router } from '@angular/router'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { FooterComponent } from '../../../shared/components/login/footer/footer.component'; +import { loginService } from '../../../service/login.service'; +import { StartHeaderComponent } from '../../../shared/components/login/start-header/start-header.component'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-register', + standalone: true, + templateUrl: './register.component.html', + styleUrl: './register.component.scss', + imports: [ + FormsModule, + CommonModule, + SmallBtnComponent, + FooterComponent, + RouterLink, + StartHeaderComponent, + TranslateModule, + ], +}) +export class RegisterComponent { + firestore: Firestore = inject(Firestore); + isChecked: boolean = false; + currentImage: string; + defaultImage = './assets/img/login/box.png'; + clickedImage = './assets/img/login/box-checked.png'; + hoverImage = './assets/img/login/box-hover.png'; + clickedHoverImage = './assets/img/login/box-checked-hover.png'; + + constructor(public loginService: loginService, private router: Router) { + this.currentImage = this.defaultImage; + } + + /** + * Handles the form submission, extracting first and last names from a full name and navigating to the avatar page. + * @param ngForm The Angular form object representing the form submission. + */ + onSubmit(ngForm: NgForm) { + const names = this.loginService.name.split(' '); + this.loginService.firstName = names[0]; + this.loginService.lastName = names.slice(1).join(' '); + this.router.navigate(['/avatar']); + } + + /** + * Toggles a checkbox state and updates the corresponding image based on the new state. + */ + toggleCheckbox() { + this.isChecked = !this.isChecked; + this.updateImage(); + } + + /** + * Updates the current image to a hover state image when the mouse is over the related component. + */ + onMouseOver() { + this.updateImage(true); + } + + /** + * Reverts the current image to its default state when the mouse is out of the related component. + */ + onMouseOut() { + this.updateImage(); + } + + /** + * Updates the image displayed based on the checkbox state and hover state. + * @param isHovering Boolean indicating if the mouse is hovering over the image component (default is false). + */ + updateImage(isHovering: boolean = false) { + if (this.isChecked) { + this.currentImage = isHovering + ? this.clickedHoverImage + : this.clickedImage; + } else { + this.currentImage = isHovering ? this.hoverImage : this.defaultImage; + } + } + + /** + * Clear the values, if user click on the arrow back button. + */ + resetValues() { + this.loginService.name = ''; + this.loginService.email = ''; + this.loginService.password = ''; + } +} diff --git a/src/app/components/main/main.component.html b/src/app/components/main/main.component.html new file mode 100644 index 0000000..dbee3bd --- /dev/null +++ b/src/app/components/main/main.component.html @@ -0,0 +1,76 @@ +
+ @if (userService.isUserLogin) { + +
+ + +
+ + +
+
+ } + +
diff --git a/src/app/components/main/main.component.scss b/src/app/components/main/main.component.scss new file mode 100644 index 0000000..c7f52f4 --- /dev/null +++ b/src/app/components/main/main.component.scss @@ -0,0 +1,129 @@ +@import "../../../styles.scss"; + +app-header { + display: block; + height: 110px; + background-color: #edeefe; +} + +.content { + display: flex; +} + +app-sidebar, +app-main-chat, +app-secondary-chat { + padding: 0 12px 12px 12px; + min-height: calc(100vh - 122px); + background-color: #edeefe; +} + +.chatBox { + display: flex; + width: 100%; + flex-grow: 1; +} + +.minusWidth { + width: calc(100% - 518px); +} + +app-main-chat { + width: 100%; +} + +app-sidebar { + max-width: 366px; +} + +app-secondary-chat { + max-width: 485px; +} + +.slideIn { + float: right; + right: 0; + transition: 0.3s linear; + animation: slideIn; +} + +.slideOut { + float: left; + margin-right: -390px; + transition: 0.3s linear; + animation: slideOut; +} + +.slideInRightWindow { + transition: 0.3s linear; + width: 100%; + animation: slideIn; +} + +@keyframes slideIn { + from { + transform: translateX(-100%); + } + + to { + width: 100%; + transform: translateX(0); + } +} + +.slideOutRightWindow { + transition: 0.3s linear; + animation: slideOut; + width: 0; + padding-right: 0; + padding-left: 0; +} + +@keyframes slideOut { + from { + transform: translateX(0); + } + + to { + transform: translateX(-100%); + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD) { + app-sidebar-toggle { + display: none; + } + + app-secondary-chat { + width: 100vw; + max-width: 100vw; + } + + app-sidebar { + width: 100vw; + max-width: 100vw; + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + app-header { + height: 80px; + } + + app-sidebar, + app-main-chat, + app-secondary-chat { + padding: 0; + min-height: calc(100vh - 80px); + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE380px) { + app-sidebar, + app-main-chat, + app-secondary-chat { + min-height: calc(100vh - 80px); + } +} diff --git a/src/app/components/main/main.component.spec.ts b/src/app/components/main/main.component.spec.ts new file mode 100644 index 0000000..6927de0 --- /dev/null +++ b/src/app/components/main/main.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MainComponent } from './main.component'; + +describe('LandingPageComponent', () => { + let component: MainComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MainComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(MainComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/main/main.component.ts b/src/app/components/main/main.component.ts new file mode 100644 index 0000000..581aea2 --- /dev/null +++ b/src/app/components/main/main.component.ts @@ -0,0 +1,114 @@ +import { + AfterViewChecked, + ChangeDetectorRef, + Component, + ElementRef, + HostListener, + OnChanges, + SimpleChanges, +} from '@angular/core'; +import { HeaderComponent } from '../../shared/components/header/header.component'; +import { ActivatedRoute, Router, RouterModule } from '@angular/router'; +import { UserService } from '../../service/user.service'; +import { SidebarComponent } from '../sidebar/sidebar.component'; +import { MainChatComponent } from '../main-chat/main-chat.component'; +import { SecondaryChatComponent } from '../secondary-chat/secondary-chat.component'; +import { ChatService } from '../../service/chat.service'; +import { ChannleService } from '../../service/channle.service'; +import { SidebarToggleComponent } from '../sidebar/sidebar-toggle/sidebar-toggle.component'; +import { CommonModule } from '@angular/common'; +import { AddNewChannelComponent } from '../sidebar/sidebar-channels/add-new-channel/add-new-channel.component'; +import { OverlayComponent } from '../../shared/components/overlay/overlay.component'; +import { ToggleBooleanService } from '../../service/toggle-boolean.service'; +import { SharedService } from '../../service/shared.service'; + +@Component({ + selector: 'app-landing-page', + standalone: true, + imports: [ + RouterModule, + HeaderComponent, + SidebarComponent, + MainChatComponent, + SecondaryChatComponent, + SidebarToggleComponent, + CommonModule, + AddNewChannelComponent, + OverlayComponent, + ], + templateUrl: './main.component.html', + styleUrl: './main.component.scss', +}) +export class MainComponent { + constructor( + public userService: UserService, + public chatService: ChatService, + public channelService: ChannleService, + private route: Router, + private router: ActivatedRoute, + private elementRef: ElementRef, + public toggleAllBooleans: ToggleBooleanService, + private sharedService: SharedService + ) {} + + currentChannel: string = ''; + viewWidth: number = 0; + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + RESPONSIVE_THRESHOLD_MAX = this.sharedService.RESPONSIVE_THRESHOLD_MAX; + + ngOnInit() { + this.ifUserLogin(); + this.routeUserId(); + this.updateViewWidth(); + } + + /** + * Checks if the user is logged in. + */ + ifUserLogin() { + if (this.userService.getCurrentUserId() === undefined) { + this.route.navigateByUrl('/login'); + } + } + + /** + * Subscribes to route params and updates the current channel. + */ + routeUserId() { + if (this.router.params.subscribe()) { + this.router.params.subscribe((params) => { + this.currentChannel = params['id']; + }); + } + } + + /** + * Listens for window resize events. + */ + @HostListener('window:resize') + onResize() { + this.updateViewWidth(); + } + + /** + * Updates the view width based on the current window width. + */ + private updateViewWidth() { + this.viewWidth = window.innerWidth; + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD) { + this.toggleAllBooleans.isSidebarOpen = false; + } else if (this.viewWidth >= this.RESPONSIVE_THRESHOLD) { + this.toggleAllBooleans.isSidebarOpen = true; + } + } + + /** + * Toggles various boolean values to control UI elements. + */ + toggleBooleans() { + this.toggleAllBooleans.openSearchWindow = false; + this.toggleAllBooleans.openSearchWindowHead = false; + this.toggleAllBooleans.selectUserInMsgBox = false; + } +} diff --git a/src/app/components/secondary-chat/secondary-chat.component.html b/src/app/components/secondary-chat/secondary-chat.component.html new file mode 100644 index 0000000..5c752af --- /dev/null +++ b/src/app/components/secondary-chat/secondary-chat.component.html @@ -0,0 +1,66 @@ +
+
+
+
+

{{ "secondary-chat.thread" | translate }}

+ @for (channel of getChannelName(); track channel) { + # {{ channel.name }} + } +
+
+ +
+
+
+ @for (chat of getSingleChat(this.chatService.isSecondaryChatId); track + chat; let i = $index) { +
+ @for (user of getChatUsers(chat.userId); track user) { + + } +
+
+

+ {{ displayCountChatAnswer(chat.id) }} + {{ "secondary-chat.answer" | translate }} +

+
+
+ } +
+ @for (chat of getChatAnswers(this.chatService.isSecondaryChatId); track + chat; let i = $index) { +
+ @for (user of getChatUsers(chat.userId); track user) { + + } +
+ } +
+
+
+
+ +
+
diff --git a/src/app/components/secondary-chat/secondary-chat.component.scss b/src/app/components/secondary-chat/secondary-chat.component.scss new file mode 100644 index 0000000..c670016 --- /dev/null +++ b/src/app/components/secondary-chat/secondary-chat.component.scss @@ -0,0 +1,129 @@ +@import "./../../../styles.scss"; + +section { + height: 100%; + width: 100%; + border-radius: 24px; + background-color: #fff; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.header { + display: flex; + align-items: center; + justify-content: space-between; + height: 40px; + padding: 24px 48px; + box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.05); +} + +.messages { + display: flex; + flex-direction: column-reverse; +} + +.content { + height: calc(100vh - 500px); + overflow-y: auto; + padding: 28px 0; +} + +.headline { + display: flex; + align-items: center; + font-size: 24px; + font-weight: 700; + span { + font-size: 14px; + font-weight: 400; + color: #797ef3; + padding-left: 12px; + } +} + +.close { + display: flex; + justify-content: center; + align-items: center; + width: 28px; + height: 28px; + cursor: pointer; + &:hover { + background-color: #edeefe; + border-radius: 100%; + img { + width: 16px; + height: 16px; + } + } + img { + width: 14px; + height: 14px; + } +} + +.spacer { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 48px; + margin-bottom: 12px; + p { + display: flex; + justify-content: center; + width: 30%; + font-size: 18px; + font-weight: 400; + color: #adb0d9; + } + .line { + width: 70%; + margin: 24px 6px; + border: 1px solid #adb0d9; + opacity: 0.4; + } +} + +.mirror { + transform: scaleX(-1); +} + +//----------- responsive --------------- + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + section { + height: calc(100vh - 80px); + border-radius: 0; + } + + .header { + height: 36px; + padding: 12px; + } + + .content { + height: calc(100vh - 350px); + } + + .spacer { + padding: 0 12px; + p { + font-size: 16px; + } + .line { + width: 70%; + margin: 24px 0px 24px 12px; + } + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE380px) { + section { + height: calc(100vh - 80px); + } + .content { + height: calc(100vh - 350px); + } +} diff --git a/src/app/components/secondary-chat/secondary-chat.component.spec.ts b/src/app/components/secondary-chat/secondary-chat.component.spec.ts new file mode 100644 index 0000000..8f29711 --- /dev/null +++ b/src/app/components/secondary-chat/secondary-chat.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SecondaryChatComponent } from './secondary-chat.component'; + +describe('SecondaryChatComponent', () => { + let component: SecondaryChatComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SecondaryChatComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SecondaryChatComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/secondary-chat/secondary-chat.component.ts b/src/app/components/secondary-chat/secondary-chat.component.ts new file mode 100644 index 0000000..d22f08e --- /dev/null +++ b/src/app/components/secondary-chat/secondary-chat.component.ts @@ -0,0 +1,164 @@ +import { + AfterViewChecked, + AfterViewInit, + Component, + ElementRef, + Input, + Renderer2, + ViewChild, +} from '@angular/core'; +import { UserService } from '../../service/user.service'; +import { ChannleService } from '../../service/channle.service'; +import { ChatService } from '../../service/chat.service'; +import { Channel } from '../../interface/channel.interface'; +import { MainComponent } from '../main/main.component'; +import { SingleChatComponent } from '../main-chat/single-chat/single-chat.component'; +import { Chat, ChatAnswers } from '../../interface/chat.interface'; +import { CommonModule } from '@angular/common'; +import { User } from '../../interface/user.interface'; +import { ChatMsgBoxComponent } from '../main-chat/chat-msg-box/chat-msg-box.component'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-secondary-chat', + standalone: true, + imports: [ + MainComponent, + SingleChatComponent, + ChatMsgBoxComponent, + CommonModule, + TranslateModule, + ], + templateUrl: './secondary-chat.component.html', + styleUrl: './secondary-chat.component.scss', +}) +export class SecondaryChatComponent implements AfterViewChecked { + @Input() currentChannel: string = ''; + @Input() viewWidth: number = 0; + @ViewChild('messageBody') messageBody: ElementRef | undefined; + sidebarLoaded: boolean = false; + isNewMessage: boolean = false; + + constructor( + public userService: UserService, + public channelService: ChannleService, + public chatService: ChatService, + private renderer: Renderer2 + ) {} + + /** + * Scrolls to the bottom if the secondary chat is open and the sidebar has not been loaded yet. + */ + ngAfterViewChecked() { + setTimeout(() => { + if (this.chatService.isSecondaryChatOpen && !this.sidebarLoaded) { + this.scrollToBottom(); + } + }, 200); + } + + /** + * Updates the isNewMessage flag and scrolls to the bottom if there's a new message. + * @param {boolean} variable - Flag indicating if there's a new message. + */ + editMsgEmitter(variable: boolean) { + this.isNewMessage = variable; + if (this.isNewMessage) { + this.scrollToBottom(); + } + } + + /** + * Scrolls the message body to the bottom. + */ + scrollToBottom(): void { + if (this.messageBody) { + const element = this.messageBody.nativeElement; + this.renderer.setProperty( + element, + 'scrollTop', + element.scrollHeight - element.clientHeight + ); + this.sidebarLoaded = true; + } + } + + /** + * Returns the count of chat answers for a given chat ID. + * @param {string} chatId - The ID of the chat. + * @returns {number} - The count of chat answers. + */ + displayCountChatAnswer(chatId: string) { + return this.chatService.getChatAnswers(chatId).length; + } + + /** + * Closes the thread chat window. + */ + closeSecondaryChat() { + this.chatService.toggleSecondaryChat('none'); + this.sidebarLoaded = false; + } + + /** + * Retrieves a single chat by its ID. + * @param {string} chatId - The ID of the chat. + * @returns {Chat[]} - An array containing the single chat. + */ + getSingleChat(chatId: string): Chat[] { + const filteredTasks = this.chatService.allChats.filter( + (chat) => chat.id == chatId + ); + return filteredTasks; + } + + /** + * Retrieves chat answers for a given chat ID. + * @param {string} chatId - The ID of the chat. + * @returns {ChatAnswers[]} - An array containing chat answers. + */ + getChatAnswers(chatId: string): ChatAnswers[] { + const filteredTasks = this.chatService.allChatAnswers.filter( + (chat) => chat.chatId === chatId + ); + + filteredTasks.sort((a, b) => b.publishedTimestamp - a.publishedTimestamp); + + return filteredTasks; + } + + /** + * Retrieves users belonging to a chat. + * @param {string} chatId - The ID of the chat. + * @returns {User[]} - An array containing users. + */ + getChatUsers(chatId: string) { + const filteredTasks = this.userService.allUsers.filter( + (user) => user.id == chatId + ); + return filteredTasks; + } + + /** + * Retrieves the name of the channel. + * @returns {Channel[]} - An array containing the channel name. + */ + getChannelName() { + const filteredTasks = this.channelService.allChannels.filter( + (channel) => channel.id == this.currentChannel + ); + return filteredTasks; + } + + /** + * Retrieves chats belonging to a channel. + * @param {string} chatId - The ID of the chat (channel). + * @returns {Chat[]} - An array containing chats. + */ + getChatChannel(chatId: string) { + const filteredTasks = this.chatService.allChats.filter( + (chat) => chat.channelId == chatId + ); + return filteredTasks; + } +} diff --git a/src/app/components/sidebar/searchbar/searchbar.component.html b/src/app/components/sidebar/searchbar/searchbar.component.html new file mode 100644 index 0000000..c2d538f --- /dev/null +++ b/src/app/components/sidebar/searchbar/searchbar.component.html @@ -0,0 +1,9 @@ +
+
+ + +
+ @if (inputValue) { +
+ } +
diff --git a/src/app/components/sidebar/searchbar/searchbar.component.scss b/src/app/components/sidebar/searchbar/searchbar.component.scss new file mode 100644 index 0000000..1b10a30 --- /dev/null +++ b/src/app/components/sidebar/searchbar/searchbar.component.scss @@ -0,0 +1,54 @@ +@import "./../../../../styles.scss"; + +section{ + position: relative; + @include displayFlex(); + .whiteBox{ + z-index: 1; + position: absolute; + top: -16px; + left: 322px; + @include displayFlex(); + width: auto; + height: 56px; + background-color: #fff; + padding: 2px 8px 2px; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 34px; + border-top-left-radius: 0; + box-shadow: rgb(111 139 169) 0px 20px 30px -10px; + input{ + width: 30vw; + height: 46px; + border-radius: 26px; + padding-right: 40px; + padding-left: 8px; + margin-right: 2px; + font-size: larger; + border: 1px solid #888dec; + font-family: "Nunito", sans-serif; + outline: none; + &:hover{ + border: 1px solid #5f66e7; + } + } + img{ + margin-left: -36px; + padding-right: 4px; + cursor: pointer; + } + } +} + +.suggestions{ + width: 200px; + height: 300px; + background-color: coral; + position: absolute; + top: 46px; + left: 360px; + border-bottom-left-radius: 25px; + border-bottom-right-radius: 25px; + z-index: 1; + box-shadow: rgb(111 139 169) 0px 20px 30px -10px; +} \ No newline at end of file diff --git a/src/app/components/sidebar/searchbar/searchbar.component.spec.ts b/src/app/components/sidebar/searchbar/searchbar.component.spec.ts new file mode 100644 index 0000000..5031dad --- /dev/null +++ b/src/app/components/sidebar/searchbar/searchbar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SearchbarComponent } from './searchbar.component'; + +describe('SearchbarComponent', () => { + let component: SearchbarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SearchbarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SearchbarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/searchbar/searchbar.component.ts b/src/app/components/sidebar/searchbar/searchbar.component.ts new file mode 100644 index 0000000..fff28e9 --- /dev/null +++ b/src/app/components/sidebar/searchbar/searchbar.component.ts @@ -0,0 +1,38 @@ +import { CommonModule } from '@angular/common'; +import { Component } from '@angular/core'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'app-searchbar', + standalone: true, + imports: [CommonModule, FormsModule], + templateUrl: './searchbar.component.html', + styleUrl: './searchbar.component.scss', +}) +export class SearchbarComponent { + inputValue: string = ''; + + constructor(private toggleBoolean: ToggleBooleanService) {} + + + /** + * Closes the search window. + * @param event The event object. + */ + closeSearchWindow(event: Event) { + this.toggleBoolean.openSearchWindow = false; + event.stopPropagation(); + this.inputValue = ''; + } + + /** + * Opens the search bar. + * @param event The event object. + */ + openSearchbar(event: Event){ + this.toggleBoolean.openSearchWindow = true; + event.stopPropagation(); + } + +} diff --git a/src/app/components/sidebar/show-all-users/show-all-users.component.html b/src/app/components/sidebar/show-all-users/show-all-users.component.html new file mode 100644 index 0000000..d760183 --- /dev/null +++ b/src/app/components/sidebar/show-all-users/show-all-users.component.html @@ -0,0 +1,34 @@ +
+
+
+

{{ "sidebar-direct-messages.members" | translate }}

+ +
+
+ @for(user of userService.getUsers(); track user){ +
+
+ + +
+

{{ user.firstName }} {{ user.lastName }}

+
+ } +
+
+
diff --git a/src/app/components/sidebar/show-all-users/show-all-users.component.scss b/src/app/components/sidebar/show-all-users/show-all-users.component.scss new file mode 100644 index 0000000..61c9caf --- /dev/null +++ b/src/app/components/sidebar/show-all-users/show-all-users.component.scss @@ -0,0 +1,66 @@ +@import "../../../../styles.scss"; + +section { + position: absolute; + top: -10px; + right: 0px; +} + +.whiteBoxAllUsersWindow { + height: fit-content; + max-height: 30vh; + width: 240px; + z-index: 4; + border-radius: 35px; + border-top-right-radius: 0; + background-color: #fff; + border: 1px solid #888dec; + padding: 24px; + @include displayFlex($g: 20px); + flex-direction: column; + + .positionHeader { + @include displayFlex($j: space-between); + font-size: 24px; + font-weight: 600; + width: 100%; + } +} + +.positionOfAllUsersInBox { + @include displayFlex($j: flex-start, $a: flex-start); + flex-direction: column; + height: fit-content; + max-height: 300px; + overflow: auto; + width: 100%; + + .user { + @include displayFlex($g: 12px); + padding: 6px; + cursor: pointer; + transition: 0.2s ease-in-out; + + &:hover { + background-color: #edeefe; + border-radius: 25px; + } + + .positionImgs { + @include displayFlex($a: flex-end); + + .avatarImg { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 50%; + } + + .onlineIcon { + width: 12px; + height: 12px; + margin-left: -10px; + } + } + } +} diff --git a/src/app/components/sidebar/show-all-users/show-all-users.component.spec.ts b/src/app/components/sidebar/show-all-users/show-all-users.component.spec.ts new file mode 100644 index 0000000..441ed21 --- /dev/null +++ b/src/app/components/sidebar/show-all-users/show-all-users.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ShowAllUsersComponent } from './show-all-users.component'; + +describe('ShowAllUsersComponent', () => { + let component: ShowAllUsersComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShowAllUsersComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShowAllUsersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/show-all-users/show-all-users.component.ts b/src/app/components/sidebar/show-all-users/show-all-users.component.ts new file mode 100644 index 0000000..04a9aea --- /dev/null +++ b/src/app/components/sidebar/show-all-users/show-all-users.component.ts @@ -0,0 +1,93 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { UserService } from '../../../service/user.service'; +import { User } from '../../../interface/user.interface'; +import { ChannleService } from '../../../service/channle.service'; +import { Router } from '@angular/router'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { ChatService } from '../../../service/chat.service'; +import { SharedService } from '../../../service/shared.service'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; + +@Component({ + selector: 'app-show-all-users', + standalone: true, + imports: [TranslateModule, SmallBtnComponent], + templateUrl: './show-all-users.component.html', + styleUrl: './show-all-users.component.scss', +}) +export class ShowAllUsersComponent { + @Input() viewWidth: number = 0; + @Output() toggleMemberListEmitter: EventEmitter = + new EventEmitter(); + + constructor( + public userService: UserService, + private route: Router, + private channelService: ChannleService, + private chatService: ChatService, + public toggleBoolean: ToggleBooleanService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + + /** + * Toggles the member list by emitting an event. + * @param {boolean} isVisible - Indicates whether the member list should be visible or not. + */ + toggleMemberList() { + this.toggleMemberListEmitter.emit(false); + } + + /** + * Closes the secondary chat window & sidebar. + */ + closeSecondaryChatAndSidebar() { + this.chatService.toggleSecondaryChat('none'); + this.toggleMemberList(); + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD) { + this.toggleBoolean.isSidebarOpen = false; + } + } + + /** + * Checks the route based on the specified user. + * @param user The user to check the route for. + */ + async checkRoute(user: User[]) { + const userId = user[0].id!; + const channelExistsBoolean = this.channelService.allPrvChannels.some( + (channel) => + (channel.creatorId === userId && + channel.talkToUserId === this.userService.getCurrentUserId()) || + (channel.creatorId === this.userService.getCurrentUserId() && + channel.talkToUserId === userId) + ); + if (!channelExistsBoolean) { + const id = await this.userService.createPrvChannel(userId); + if (id) { + this.route.navigateByUrl(`main/${id}`); + } + } + this.getRouteToPrvChat(userId, channelExistsBoolean); + } + + /** + * Navigates to the private chat route based on the specified user. + * @param userId The ID of the user. + * @param channelExistsBoolean A boolean indicating whether the channel exists. + */ + getRouteToPrvChat(userId: string, channelExistsBoolean: boolean) { + if (channelExistsBoolean) { + const existingChannel = this.channelService.allPrvChannels.find( + (channel) => + (channel.creatorId === userId && + channel.talkToUserId === this.userService.getCurrentUserId()) || + (channel.creatorId === this.userService.getCurrentUserId() && + channel.talkToUserId === userId) + ); + this.route.navigateByUrl(`main/${existingChannel!.id}`); + } + } +} diff --git a/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.html b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.html new file mode 100644 index 0000000..2b39068 --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.html @@ -0,0 +1,150 @@ +
+
+ +
+ @if (!showNextWindow) { +
+
+

{{ 'add-new-channel.header' | translate }}

+ +
+ {{ 'add-new-channel.info' | translate }} +
+

{{ 'add-new-channel.header2' | translate }}

+   + {{ 'add-new-channel.required' | translate }} + @if (chechIfChannelExist(channelName)) { +

{{ 'add-new-channel.warning' | translate }}

+ } + +
+ +
+

{{ 'add-new-channel.description' | translate }}

+   + {{ 'add-new-channel.optional' | translate }} +
+ +
+ +
+
+ } @if (showNextWindow || showNextWindowMobile) { +
+
+

{{ 'add-new-channel.addPeople' | translate }}

+ +
+
+ +

{{ 'add-new-channel.addAll' | translate }}  {{ 'add-new-channel.devspace' | translate }}

+
+
+ +

{{ 'add-new-channel.add' | translate }}

+
+
+
+ +

{{ user.firstName }} {{ user.lastName }}

+ +
+ +
+
+ @for(user of getSearchedUser; track user){ +
+
+ + +
+

{{ user.firstName }} {{ user.lastName }}

+
+ } +
+
+
+
+ +
+
+ } +
diff --git a/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.scss b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.scss new file mode 100644 index 0000000..77f049e --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.scss @@ -0,0 +1,343 @@ +@import "../../../../../styles.scss"; + +.darkBackground { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + z-index: 2; +} + +.grayBackground { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + z-index: 4; +} + +.infoMsg { + font-size: 18px; + font-weight: 400; + padding: 12px 0; +} + +.newChannelDescription { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + @include displayFlex(); + font-family: "Nunito"; +} + +.whiteWindow { + width: 60vw; + max-width: 872px; + height: auto; + background-color: #fff; + border-radius: 25px; + z-index: 3; + @include displayFlex($a: flex-start, $g: 8px); + flex-direction: column; + text-align: left; + padding: 32px; +} + +.posiotionHeader { + @include displayFlex($j: space-between); + width: 100%; + p { + font-size: 24px; + font-weight: 700; + } +} + +.textfieldStyle { + width: calc(100% - 40px); + border: 1px solid #888dec; + overflow: auto; + scrollbar-width: none; + outline: none; + height: 22px; + padding: 18px 20px; + border-radius: 40px; + opacity: 0px; + transition: 0.3s ease-in-out; + font-size: 18px; + font-weight: 400; + margin: 12px 0; + &:hover { + border: 1px solid #2c36f0; + } +} +textarea { + resize: none; + min-height: 72px; +} +.descriptionBox { + @include displayFlex(); + position: relative; + p { + font-size: 18px; + font-weight: 700; + padding-top: 6px; + } + span { + font-size: 16px; + font-weight: 400; + padding-top: 6px; + } + .warning{ + font-size: 18px; + font-weight: 500; + padding-top: 6px; + color: #ff0000; + margin-left: 26px; + } +} +.hashtag { + position: absolute; + bottom: -58px; + left: 18px; + filter: brightness(0) saturate(100%) invert(45%) sepia(22%) saturate(0%) + hue-rotate(159deg) brightness(97%) contrast(88%); +} +.hashtagPadding { + width: calc(100% - 60px); + padding: 18px 20px 18px 40px !important; +} + +.btnBox { + width: 100%; + @include displayFlex($j: flex-end); + .furterBtnClass { + width: 120px; + height: 48px; + background-color: white; + border: 1px solid #888dec; + border-radius: 25px; + font-size: larger; + color: #444df2; + transition: 0.3s ease-in-out; + &:hover { + background-color: #444df2; + color: white; + cursor: pointer; + } + } +} + +.smalWhiteBox { + padding: 32px; + width: 48vw; + height: auto; + background-color: #fff; + border-radius: 25px; + z-index: 3; + display: flex; + flex-direction: column; + gap: 16px; + position: relative; + .positionSelectionBtn { + @include displayFlex($j: flex-start, $g: 12px); + p { + display: flex; + font-size: 18px; + font-weight: 400; + } + span { + font-size: 18px; + font-weight: 400; + color: #535af1; + } + img { + cursor: pointer; + } + } + .addedUserBox { + display: flex; + flex-wrap: wrap; + height: auto; + max-width: 100%; + border: 1px solid #888dec; + background-color: white; + border-radius: 25px; + transition: 0.3s ease-in-out; + position: relative; + &:hover { + border: 1px solid #2c36f0; + } + .userPosition { + @include displayFlex($g: 8px); + padding: 4px; + padding-left: 8px; + padding-right: 8px; + background-color: #edeefe; + border-radius: 25px; + border-radius: 25px; + margin: 4px; + .avatarImg { + width: 32px; + height: 32px; + object-fit: cover; + border-radius: 50%; + } + .imgClose { + width: 12px; + object-fit: contain; + transition: 0.1s ease-in-out; + cursor: pointer; + &:hover { + scale: 1.1; + filter: brightness(0) saturate(100%) invert(8%) sepia(96%) + saturate(6339%) hue-rotate(1deg) brightness(102%) contrast(109%); + } + } + } + .inputfieldStyle { + width: auto; + flex-grow: 1; + outline: none; + border: none; + border-radius: 25px; + height: 26px; + padding: 12px; + height: auto; + font-size: larger; + } + } + .positionCreateBtn { + width: 100%; + @include displayFlex($j: flex-end); + } + + .textfieldStyle { + width: calc(100% - 24px); + border: 1px solid #888dec; + outline: none; + height: 26px; + border-radius: 25px; + padding: 8px; + padding-left: 12px; + padding-right: 12px; + height: auto; + font-size: larger; + transition: 0.3s ease-in-out; + &:hover { + border: 1px solid #2c36f0; + } + } + button { + @include displayFlex(); + width: 120px; + height: 48px; + background-color: white; + border: 1px solid #888dec; + border-radius: 25px; + font-size: larger; + color: #444df2; + transition: 0.3s ease-in-out; + &:hover { + background-color: #444df2; + color: white; + cursor: pointer; + } + } +} + +.showSearchedUsersWindow { + width: auto; + max-height: 222px; + overflow: auto; + scrollbar-width: none; + background-color: white; + border-radius: 25px; + border-top-left-radius: 0; + border: 1px solid #888dec; + position: absolute; + top: 88%; + left: 24px; + padding: 8px; + text-align: start; + .positionOfAllUsersInBox { + @include displayFlex($a: flex-start); + flex-direction: column; + .user { + @include displayFlex($g: 12px); + padding: 6px; + margin-bottom: 6px; + cursor: pointer; + transition: 0.2s ease-in-out; + &:hover { + background-color: #edeefe; + border-radius: 25px; + } + .positionImgs { + @include displayFlex($a: flex-end); + .avatarImg { + width: 40px; + height: 40px; + object-fit: cover; + border-radius: 50%; + } + .onlineIcon { + width: 12px; + height: 12px; + border-radius: 50%; + margin-left: -10px; + } + } + } + } +} + +.headerAddPeople { + @include displayFlex($j: space-between); +} + +.disabledBtn { + background-color: #22222242; + border: none; + font-size: larger; + color: #fff; + width: 120px; + height: 48px; + border-radius: 25px; + font-size: larger; +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .whiteWindow { + justify-content: start; + width: 100vw; + height: calc(100vh - 64px); + border-radius: 0; + } + + .smalWhiteBox { + position: absolute; + bottom: 0; + left: 0; + right: 0; + z-index: 5; + width: calc(100vw - 64px); + height: fit-content; + border-top-left-radius: 25px; + border-top-right-radius: 25px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + box-shadow: 0px -3px 10px 0px #00000033; + } + + .showSearchedUsersWindow { + max-height: 80px; + } +} diff --git a/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.spec.ts b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.spec.ts new file mode 100644 index 0000000..03b8ee8 --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddNewChannelComponent } from './add-new-channel.component'; + +describe('AddNewChannelComponent', () => { + let component: AddNewChannelComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AddNewChannelComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AddNewChannelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.ts b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.ts new file mode 100644 index 0000000..ebc2e2b --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/add-new-channel/add-new-channel.component.ts @@ -0,0 +1,219 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { ChannleService } from '../../../../service/channle.service'; +import { SmallBtnComponent } from '../../../../shared/components/small-btn/small-btn.component'; +import { FormsModule } from '@angular/forms'; +import { UserService } from '../../../../service/user.service'; +import { User } from '../../../../interface/user.interface'; +import { Channel } from '../../../../interface/channel.interface'; +import { Router } from '@angular/router'; +import { SharedService } from '../../../../service/shared.service'; +import { ToggleBooleanService } from '../../../../service/toggle-boolean.service'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-add-new-channel', + standalone: true, + imports: [CommonModule, SmallBtnComponent, FormsModule, TranslateModule], + templateUrl: './add-new-channel.component.html', + styleUrl: './add-new-channel.component.scss', +}) +export class AddNewChannelComponent { + @Input() viewWidth: number = 0; + + currentDate: string = new Date().toISOString().split('T')[0]; + changeImg: boolean = false; + userName: string = ''; + showExistenUsers: boolean = false; + getSearchedUser: User[] = []; + channelName: string = ''; + channelDescription: string = ''; + privatChannel: boolean = false; + getSelectedUsers: User[] = []; + selectedUsers: string[] = []; + testarray: string[] = []; + channelIsPrivat: boolean = false; + showNextWindow: boolean = false; + showNextWindowMobile: boolean = false; + + constructor( + public channelService: ChannleService, + public userService: UserService, + public route: Router, + private sharedService: SharedService, + private toggleBooleanService: ToggleBooleanService + ) {} + + RESPONSIVE_THRESHOLD_MOBILE = this.sharedService.RESPONSIVE_THRESHOLD_MOBILE; + + /** + * Toggles the visibility of the add channel box. + */ + toggleShowAddChannelBox() { + this.channelService.showAddChannelBox = + !this.channelService.showAddChannelBox; + this.showNextWindow = false; + this.showNextWindowMobile = false; + this.channelName = ''; + this.channelDescription = ''; + } + + /** + * Toggles the visibility of the next window. + */ + createNewChannel() { + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD_MOBILE) { + this.showNextWindowMobile = true; + } else { + this.showNextWindow = true; + } + } + + /** + * Toggles the button to true. + */ + toggleBtnTrue() { + this.changeImg = true; + this.channelIsPrivat = true; + } + + /** + * Toggles the button to false. + */ + toggleBtnFalse() { + this.changeImg = false; + this.channelIsPrivat = false; + } + + /** + * Filters users based on input. + * @param userName The name of the user to filter. + */ + filterUsers(userName: string) { + this.showExistenUsers = true; + this.getSearchedUser = []; + const searchedUser = userName.toLowerCase().trim(); + const filteredUsers = this.userService.getUsers().filter((user) => { + const fullName = `${user.firstName} ${user.lastName}`.toLowerCase(); + return ( + fullName.includes(searchedUser) && + user.id !== this.userService.getCurrentUserId() + ); + }); + this.getSearchedUser.push(...filteredUsers); + } + + /** + * Chooses a user. + * @param user The user to choose. + */ + chooseUser(user: User) { + const isUserAlreadySelected = this.getSelectedUsers.some( + (selectedUser) => selectedUser.id === user.id + ); + + if (!isUserAlreadySelected) { + this.selectedUsers.push(user.id!); + this.getSelectedUsers.push(user); + console.log('this.selectedUsers', this.selectedUsers); + } else { + console.log('User already selected!'); + } + this.userName = ''; + this.showExistenUsers = false; + } + + /** + * Removes the current user. + * @param index The index of the user to remove. + */ + spliceCurrentUser(index: number) { + this.getSelectedUsers.splice(index, 1); + this.showExistenUsers = false; + } + + /** + * Toggles the added user box. + */ + toggleAddedUserBox() { + this.showExistenUsers = false; + } + + /** + * Checks if the channel name is valid. + * @param channelName The name of the channel to check. + */ + checkIfChannelNameIsValid(channelName: string) { + const channelNameLenght = channelName.length; + if (channelNameLenght >= 6 && !this.chechIfChannelExist(channelName)) { + this.channelService.btnIsValid = true; + } else { + this.channelService.btnIsValid = false; + } + } + + /** + * Check if channel is allready existing. + * @param channelName + * @returns + */ + chechIfChannelExist(channelName: string){ + const filterChannel = this.channelService.allChannels.some(channel => channel.name === channelName); + if (filterChannel) { + return true; + } else { + return false; + } + } + + /** + * Adds a new channel. + */ + async addNewChannel() { + const newChannel: Channel = { + name: this.channelName, + description: this.channelDescription || '', + creator: this.userService.getCurrentUserId(), + privatChannel: this.privatChannel, + hashtag: this.channelName, + createdDate: this.currentDate, + addedUser: this.checkUserArray(), + }; + const channelId = await this.channelService.createNewChannel( + newChannel, + 'channels' + ); + this.openAddNewChannelWindow(); + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD_MOBILE) { + this.toggleBooleanService.isSidebarOpen = false; + } + this.route.navigateByUrl(`main/${channelId}`); + } + + /** + * Checks the user array. + * @returns The user array. + */ + checkUserArray() { + if (this.channelIsPrivat) { + return [...this.selectedUsers, this.userService.getCurrentUserId()]; + } else { + return this.userService.getUserIDs; + } + } + + /** + * Opens the add new channel window. + */ + openAddNewChannelWindow() { + this.channelService.showAddChannelBox = + !this.channelService.showAddChannelBox; + this.channelName = ''; + this.channelDescription = ''; + this.channelService.btnIsValid = false; + this.getSelectedUsers = []; + this.selectedUsers = []; + this.showNextWindow = false; + this.showNextWindowMobile = false; + } +} diff --git a/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.html b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.html new file mode 100644 index 0000000..c26f8f6 --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.html @@ -0,0 +1,59 @@ +
+
+
+ + +

{{ 'sidebar-channels.channel' | translate }}

+
+
+ + +
+
+
+ @for (channel of getChannels(); track channel; let i = $index) { +
+ +

{{ channel.name }}

+
+ } +
+
+
+ +
+

{{ 'sidebar-channels.addChannel' | translate }}

+
+ +
diff --git a/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.scss b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.scss new file mode 100644 index 0000000..3266cbd --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.scss @@ -0,0 +1,168 @@ +@import "../../../../styles.scss"; + +section { + display: flex; + flex-direction: column; + min-width: 300px; +} + +.headline { + display: flex; + justify-content: space-between; + padding-bottom: 12px; +} + +.btn { + display: flex; + align-items: center; + justify-content: right; + padding-right: 12px; + width: 60px; +} + +.headlineText { + display: flex; + align-items: center; + cursor: pointer; + .arrowImg { + width: 10px; + height: 10px; + object-fit: contain; + } + img { + &:first-child { + padding-right: 24px; + } + + &:nth-child(2) { + padding-right: 6px; + } + } + + p { + font-size: 20px; + font-weight: 700; + } + + &:hover { + filter: invert(25%) sepia(100%) saturate(1833%) hue-rotate(230deg) + brightness(101%) contrast(89%); + } +} + +.boxOfAllChannels { + max-height: 16vh; + overflow: auto; + .channelName { + display: flex; + align-items: center; + margin: 12px 24px; + padding: 8px; + max-width: fit-content; + cursor: pointer; + + img { + width: 16px; + height: 16px; + padding-right: 12px; + margin-left: 4px; + } + + p { + font-size: 18px; + font-weight: 400; + padding-right: 8px; + } + + &:hover, + &:focus { + background-color: #edeefe; + border-radius: 24px; + } + } +} + +.active { + cursor: default; + background-color: #edeefe; + border-radius: 24px; +} + +.addChannel { + display: flex; + align-items: center; + margin: 12px 24px; + padding: 8px; + cursor: pointer; + .circle { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + margin-left: 6px; + + img { + width: 20px; + height: 20px; + padding-right: 12px; + } + } + + p { + font-size: 18px; + font-weight: 400; + padding-left: 2px; + } + + &:hover { + filter: invert(25%) sepia(100%) saturate(1833%) hue-rotate(230deg) + brightness(101%) contrast(89%); + + .circle { + img { + width: 22px; + height: 24px; + } + } + } +} + +.showAllChanneld { + animation-name: slideIn; + overflow: auto; + transition: max-height 0.3s ease-in-out; + max-height: 25vh; +} + +@keyframes slideIn { + from { + max-height: 0; + } + + to { + max-height: 16vh; + } +} + +.hideAllChannels { + animation-name: slideOut; + transition: max-height 0.3s ease-in-out; + max-height: 0; +} + +@keyframes slideOut { + from { + max-height: 16vh; + } + + to { + max-height: 0; + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE380px) { + .showAllChanneld { + max-height: 16vh; + } +} diff --git a/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.spec.ts b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.spec.ts new file mode 100644 index 0000000..0a3290c --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SidebarChannelsComponent } from './sidebar-channels.component'; + +describe('SidebarChannelsComponent', () => { + let component: SidebarChannelsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SidebarChannelsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SidebarChannelsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.ts b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.ts new file mode 100644 index 0000000..a8905d9 --- /dev/null +++ b/src/app/components/sidebar/sidebar-channels/sidebar-channels.component.ts @@ -0,0 +1,87 @@ +import { Component, Input } from '@angular/core'; +import { ChannleService } from '../../../service/channle.service'; +import { Channel, publicChannels } from '../../../interface/channel.interface'; +import { RouterLink } from '@angular/router'; +import { ChatService } from '../../../service/chat.service'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { AddNewChannelComponent } from './add-new-channel/add-new-channel.component'; +import { UserService } from '../../../service/user.service'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { SharedService } from '../../../service/shared.service'; + +@Component({ + selector: 'app-sidebar-channels', + standalone: true, + imports: [ + RouterLink, + SmallBtnComponent, + CommonModule, + FormsModule, + AddNewChannelComponent, + TranslateModule, + ], + templateUrl: './sidebar-channels.component.html', + styleUrl: './sidebar-channels.component.scss', +}) +export class SidebarChannelsComponent { + @Input() currentChannel: string = ''; + @Input() viewWidth: number = 0; + + minimizeChannels: boolean = true; + + constructor( + public channelService: ChannleService, + public chatService: ChatService, + public userService: UserService, + public toggleBoolean: ToggleBooleanService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + + /** + * Toggles the visibility of channels. + */ + minimizeAllChannels() { + this.minimizeChannels = !this.minimizeChannels; + } + + /** + * Opens the add new channel window. + */ + openAddChannelWindow() { + this.channelService.btnIsValid = false; + this.channelService.showAddChannelBox = true; + } + + /** + * Closes the secondary chat window & sidebar. + */ + closeSecondaryChatAndSidebar() { + this.chatService.toggleSecondaryChat('none'); + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD) { + this.toggleBoolean.isSidebarOpen = false; + } + } + + /** + * The channels accessible to the current user are scrolled, public channels are at the top + * @returns {Channel[]} An array of Channel objects. + */ + getChannels(): Channel[] { + const userChannels = this.channelService.allChannels.filter((channel) => + channel.addedUser.includes(this.userService.getCurrentUserId()) + ); + const priorityChannels = userChannels.filter((channel) => + publicChannels.includes(channel.id!) + ); + const otherChannels = userChannels.filter( + (channel) => !priorityChannels.includes(channel) + ); + + return [...priorityChannels, ...otherChannels]; + } +} diff --git a/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.html b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.html new file mode 100644 index 0000000..79e1f40 --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.html @@ -0,0 +1,81 @@ +
+ @for (directMessage of + displayPrivateChat(this.userService.getCurrentUserId()); track directMessage; + let i = $index) { + + @if (directMessage.creatorId === this.userService.getCurrentUserId() && + directMessage.talkToUserId === this.userService.getCurrentUserId()) { @for + (user of getChatUsers(directMessage.creatorId); track user){ +
+
+ + +
+

+ {{ user.firstName }} {{ user.lastName }} ({{ + "sidebar-direct-messages-user.you" | translate + }}) +

+
+ } } + + @if (directMessage.talkToUserId === this.userService.getCurrentUserId() && + directMessage.creatorId !== this.userService.getCurrentUserId()) { @for (user + of getChatUsers(directMessage.creatorId); track user){ +
+
+ + +
+

{{ user.firstName }} {{ user.lastName }}

+
+ } } + + @if (directMessage.creatorId === this.userService.getCurrentUserId() && + directMessage.talkToUserId !== this.userService.getCurrentUserId()) { @for + (user of getChatUsers(directMessage.talkToUserId); track user){ +
+
+ + +
+

{{ user.firstName }} {{ user.lastName }}

+
+ } } } +
diff --git a/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.scss b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.scss new file mode 100644 index 0000000..ba48864 --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.scss @@ -0,0 +1,59 @@ +@import "../../../../styles.scss"; + +section { + display: flex; + flex-direction: column; + max-height: 27vh; + margin: 18px 0 0 12px; + overflow: auto; + min-width: 300px; +} + +.user { + display: flex; + align-items: center; + margin: 6px; + padding: 6px; + max-width: fit-content; + cursor: pointer; + .imgBox { + display: flex; + align-items: flex-end; + .userImg { + width: 50px; + height: 50px; + object-fit: cover; + border-radius: 50%; + } + .onlineIcon { + width: 16px; + height: 16px; + border-radius: 50%; + margin-left: -12px; + } + } + p { + font-size: 18px; + font-weight: 400; + padding: 0 12px 0 18px; + text-align: left; + } + &:hover, + &:active { + background-color: #edeefe; + border-radius: 36px; + } +} + +.active { + cursor: default; + background-color: #edeefe; + border-radius: 36px; +} + + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE380px) { + section { + max-height: 22vh; + } +} \ No newline at end of file diff --git a/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.spec.ts b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.spec.ts new file mode 100644 index 0000000..bd02fcf --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SidebarDirectMessagesUserComponent } from './sidebar-direct-messages-user.component'; + +describe('SidebarDirectMessagesUserComponent', () => { + let component: SidebarDirectMessagesUserComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SidebarDirectMessagesUserComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SidebarDirectMessagesUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.ts b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.ts new file mode 100644 index 0000000..c3e8028 --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages-user/sidebar-direct-messages-user.component.ts @@ -0,0 +1,117 @@ +import { Component, Input } from '@angular/core'; +import { UserService } from '../../../service/user.service'; +import { CommonModule } from '@angular/common'; +import { ChannleService } from '../../../service/channle.service'; +import { RouterLink } from '@angular/router'; +import { ChatService } from '../../../service/chat.service'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; +import { SharedService } from '../../../service/shared.service'; +import { PrvChannel } from '../../../interface/channel.interface'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-sidebar-direct-messages-user', + standalone: true, + imports: [CommonModule, RouterLink, TranslateModule], + templateUrl: './sidebar-direct-messages-user.component.html', + styleUrl: './sidebar-direct-messages-user.component.scss', +}) +export class SidebarDirectMessagesUserComponent { + @Input() currentChannel: string = ''; + @Input() viewWidth: number = 0; + + constructor( + public userService: UserService, + private channelService: ChannleService, + public chatService: ChatService, + public toggleBoolean: ToggleBooleanService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + + /** + * Get users for private chat. + * @param userId The ID of the user. + * @returns Array of User objects. + */ + getChatUsers(userId: string) { + const filteredTasks = this.userService + .getUsers() + .filter((user) => user.id == userId); + return filteredTasks; + } + + /** + * Closes the secondary chat window & sidebar. + */ + closeSecondaryChatAndSidebar() { + this.chatService.toggleSecondaryChat('none'); + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD) { + this.toggleBoolean.isSidebarOpen = false; + } + } + + /** + * Display private chat channels associated with the provided user ID. + * @param {string} userId - The ID of the user for whom private chat channels are to be displayed. + * @returns {Array} - An array of unique private chat channels sorted based on specific criteria. + */ + displayPrivateChat(userId: string) { + const creatorChannels = this.channelService.allPrvChannels.filter( + (channel) => channel.creatorId === userId + ); + const talkToUserChannels = this.channelService.allPrvChannels.filter( + (channel) => channel.talkToUserId === userId + ); + const allChannels = creatorChannels.concat(talkToUserChannels); + + // Sort the channels so that the channel with corrent logged in userId comes first + this.sortUserPrivatChannel(allChannels, userId); + const firstChannel = allChannels.shift(); + + // Sort the channels based on the last date of the chat + this.sortAllAnotherChannel(allChannels, userId); + + if (firstChannel) { + allChannels.unshift(firstChannel); + } + + return Array.from(new Set(allChannels)); + } + + /** + * Sorts an array if it is the own user channel + * @param {PrvChannel[]} allChannels - Array of private channels to sort. + * @param {string} userId - The ID of the user. + */ + sortUserPrivatChannel(allChannels: PrvChannel[], userId: string) { + allChannels.sort((a, b) => { + if (a.creatorId === userId) return -1; + if (b.creatorId === userId) return 1; + return 0; + }); + } + + /** + * Sorts an array of private channels based on the last message's timestamp. + * @param {PrvChannel[]} allChannels - Array of private channels to sort. + * @param {string} userId - The ID of the user. + */ + sortAllAnotherChannel(allChannels: PrvChannel[], userId: string) { + allChannels.sort((a, b) => { + const lastMessageA = this.chatService.allChats + .filter((chat) => chat.channelId === a.id) + .sort((x, y) => y.publishedTimestamp - x.publishedTimestamp)[0]; + + const lastMessageB = this.chatService.allChats + .filter((chat) => chat.channelId === b.id) + .sort((x, y) => y.publishedTimestamp - x.publishedTimestamp)[0]; + + if (!lastMessageA) return 1; + if (!lastMessageB) return -1; + + return lastMessageB.publishedTimestamp - lastMessageA.publishedTimestamp; + }); + } +} diff --git a/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.html b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.html new file mode 100644 index 0000000..222f8d1 --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.html @@ -0,0 +1,39 @@ +
+
+
+ + +

{{ "sidebar-direct-messages.messages" | translate }}

+
+ @if (!showAllUsers) { +
+ + +
+ } @if (showAllUsers) { +
+ +
+ } +
+ +
diff --git a/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.scss b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.scss new file mode 100644 index 0000000..3d7a435 --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.scss @@ -0,0 +1,87 @@ +section { + display: flex; + flex-direction: column; + min-width: 300px; +} + +.headline { + display: flex; + justify-content: space-between; + align-items: center; +} + +.invisibleDiv { + display: flex; + justify-content: space-between; + align-items: center; + position: relative; +} + +.btnAllUsersWindow { + display: flex; + align-items: center; + justify-content: right; + padding-right: 12px; + width: 60px; +} + +.headlineText { + display: flex; + align-items: center; + cursor: pointer; + .arrowImg { + width: 10px; + height: 10px; + object-fit: contain; + } + img { + &:first-child { + padding-right: 24px; + } + &:nth-child(2) { + padding-right: 6px; + } + } + p { + font-size: 20px; + font-weight: 700; + } + &:hover { + filter: invert(25%) sepia(100%) saturate(1833%) hue-rotate(230deg) + brightness(101%) contrast(89%); + } +} + +.showAllUsers { + animation-name: slideIn; + transition: max-height 0.3s ease-in-out; + overflow: hidden; + max-height: 32vh; +} + +@keyframes slideIn { + from { + height: 0; + } + + to { + height: 100%; + } +} + +.hideAllUsers { + transition: max-height 0.3s ease-in-out; + animation-name: slideOut; + overflow: hidden; + max-height: 0; +} + +@keyframes slideOut { + from { + max-height: 0; + } + + to { + max-height: 32vh; + } +} diff --git a/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.spec.ts b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.spec.ts new file mode 100644 index 0000000..e77b171 --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SidebarDirectMessagesComponent } from './sidebar-direct-messages.component'; + +describe('SidebarDirectMessagesComponent', () => { + let component: SidebarDirectMessagesComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SidebarDirectMessagesComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SidebarDirectMessagesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.ts b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.ts new file mode 100644 index 0000000..979ef45 --- /dev/null +++ b/src/app/components/sidebar/sidebar-direct-messages/sidebar-direct-messages.component.ts @@ -0,0 +1,64 @@ +import { Component, HostListener, Input } from '@angular/core'; +import { SidebarDirectMessagesUserComponent } from '../sidebar-direct-messages-user/sidebar-direct-messages-user.component'; +import { CommonModule } from '@angular/common'; +import { TranslateModule } from '@ngx-translate/core'; +import { SmallBtnComponent } from '../../../shared/components/small-btn/small-btn.component'; +import { ShowAllUsersComponent } from '../show-all-users/show-all-users.component'; + +@Component({ + selector: 'app-sidebar-direct-messages', + standalone: true, + imports: [ + SidebarDirectMessagesUserComponent, + CommonModule, + TranslateModule, + SmallBtnComponent, + ShowAllUsersComponent, + ], + templateUrl: './sidebar-direct-messages.component.html', + styleUrl: './sidebar-direct-messages.component.scss', +}) +export class SidebarDirectMessagesComponent { + @Input() currentChannel: string = ''; + @Input() viewWidth: number = 0; + + minimizeUsers: boolean = false; + showAllUsers: boolean = false; + + /** + * Toggles the visibility of direct message users. + */ + minimizeAllUsers() { + this.minimizeUsers = !this.minimizeUsers; + } + + /** + * Toggles the state of the member list emitter. + * @param {boolean} variable - The boolean variable determining the state of the member list emitter. + */ + toggleMemberListEmitter(variable: boolean) { + this.showAllUsers = variable; + } + + /** + * Toggles the visibility of the all users window. + */ + toggleAllUsersWindow() { + this.showAllUsers = !this.showAllUsers; + } + + /** + * Checks if the click event happens outside of the all users window, and closes it if necessary. + * @param {MouseEvent} event - The mouse event object. + */ + @HostListener('document:click', ['$event']) + checkOpenAllUsersWindow(event: MouseEvent) { + const targetElement = event.target as HTMLElement; + if ( + !targetElement.closest('.whiteBoxAllUsersWindow') && + !targetElement.closest('.btnAllUsersWindow') + ) { + this.showAllUsers = false; + } + } +} diff --git a/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.html b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.html new file mode 100644 index 0000000..2cc8864 --- /dev/null +++ b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.html @@ -0,0 +1,6 @@ +
+ +
diff --git a/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.scss b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.scss new file mode 100644 index 0000000..35cfde0 --- /dev/null +++ b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.scss @@ -0,0 +1,44 @@ +section { + display: flex; + align-items: center; + justify-content: center; + position: fixed; + bottom: 10vh; + left: 0; + width: 40px; + height: 306px; + border-top-right-radius: 24px; + border-bottom-right-radius: 24px; + background-color: #fff; + box-shadow: 10px 5px 5px rgba($color: #000000, $alpha: 0.2); + z-index: 1; + cursor: pointer; + &:hover { + box-shadow: 10px 5px 5px rgba($color: #000000, $alpha: 0.3); + p { + color: #535af1; + } + img { + filter: brightness(0) saturate(100%) invert(29%) sepia(86%) + saturate(1584%) hue-rotate(224deg) brightness(96%) contrast(96%); + } + } +} + +.menu { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + p { + font-size: 20px; + font-weight: 500; + writing-mode: vertical-lr; + transform: scale(-1); + padding-bottom: 12px; + } + img { + width: 18px; + height: 18px; + } +} diff --git a/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.spec.ts b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.spec.ts new file mode 100644 index 0000000..b03c60c --- /dev/null +++ b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SidebarToggleComponent } from './sidebar-toggle.component'; + +describe('SidebarToggleComponent', () => { + let component: SidebarToggleComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SidebarToggleComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SidebarToggleComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.ts b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.ts new file mode 100644 index 0000000..ffeac38 --- /dev/null +++ b/src/app/components/sidebar/sidebar-toggle/sidebar-toggle.component.ts @@ -0,0 +1,43 @@ +import { Component, Input } from '@angular/core'; +import { ChatService } from '../../../service/chat.service'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-sidebar-toggle', + standalone: true, + imports: [TranslateModule], + templateUrl: './sidebar-toggle.component.html', + styleUrl: './sidebar-toggle.component.scss', +}) +export class SidebarToggleComponent { + @Input() viewWidth: number = 0; + + constructor( + private chatService: ChatService, + private toggleBoolean: ToggleBooleanService + ) {} + + + /** + * Toggles the sidebar visibility and checks the view width. + */ + toggleSidebar() { + this.toggleBoolean.isSidebarOpen = !this.toggleBoolean.isSidebarOpen; + this.checkViewWidth(); + } + + + /** + * Checks the view width and adjusts sidebar and chat states accordingly. + */ + checkViewWidth() { + if (this.viewWidth <= 1900 && this.chatService.isSecondaryChatOpen) { + this.toggleBoolean.isSidebarOpen = true; + } + if (this.viewWidth <= 1900) { + this.chatService.isSecondaryChatId = ''; + this.chatService.isSecondaryChatOpen = false; + } + } +} diff --git a/src/app/components/sidebar/sidebar.component.html b/src/app/components/sidebar/sidebar.component.html new file mode 100644 index 0000000..1734d18 --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.html @@ -0,0 +1,45 @@ +
+ @if (viewWidth >= RESPONSIVE_THRESHOLD) { +
+ +
+ + +
+
+ } @else { + + } + +
+ +
+
+ +
+
diff --git a/src/app/components/sidebar/sidebar.component.scss b/src/app/components/sidebar/sidebar.component.scss new file mode 100644 index 0000000..ba59d12 --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.scss @@ -0,0 +1,61 @@ +@import "./../../../styles.scss"; + +section { + height: 100%; + border-radius: 24px; + background-color: #fff; +} + +.btn { + display: flex; + align-items: center; + justify-content: right; + padding-right: 12px; + width: 60px; +} + +.headline { + display: flex; + justify-content: space-between; + align-items: center; + .logo { + display: flex; + justify-content: left; + align-items: center; + img { + width: 60px; + height: 60px; + background-color: black; + border-radius: 100%; + margin-right: 12px; + } + p { + font-size: 24px; + font-weight: 700; + } + } +} + +.channels, +.directMessages, +.headline { + padding: 36px 36px 0 36px; +} + +.searchBar { + padding: 12px; +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + section { + border-radius: 0; + } + + .channels, + .directMessages, + .headline { + padding: 12px; + } +} diff --git a/src/app/components/sidebar/sidebar.component.spec.ts b/src/app/components/sidebar/sidebar.component.spec.ts new file mode 100644 index 0000000..85e49bd --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SidebarComponent } from './sidebar.component'; + +describe('SidebarComponent', () => { + let component: SidebarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SidebarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SidebarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sidebar/sidebar.component.ts b/src/app/components/sidebar/sidebar.component.ts new file mode 100644 index 0000000..0946046 --- /dev/null +++ b/src/app/components/sidebar/sidebar.component.ts @@ -0,0 +1,75 @@ +import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute, RouterModule } from '@angular/router'; +import { SidebarChannelsComponent } from './sidebar-channels/sidebar-channels.component'; +import { SidebarDirectMessagesComponent } from './sidebar-direct-messages/sidebar-direct-messages.component'; +import { SmallBtnComponent } from '../../shared/components/small-btn/small-btn.component'; +import { CommonModule } from '@angular/common'; +import { ChannleService } from '../../service/channle.service'; +import { SearchbarComponent } from './searchbar/searchbar.component'; +import { ToggleBooleanService } from '../../service/toggle-boolean.service'; +import { ChatService } from '../../service/chat.service'; +import { SharedService } from '../../service/shared.service'; +import { SearchBarComponent } from '../../shared/components/header/search-bar/search-bar.component'; +@Component({ + selector: 'app-sidebar', + standalone: true, + imports: [ + RouterModule, + SidebarChannelsComponent, + SidebarDirectMessagesComponent, + SmallBtnComponent, + CommonModule, + SearchbarComponent, + SearchBarComponent, + ], + templateUrl: './sidebar.component.html', + styleUrl: './sidebar.component.scss', +}) +export class SidebarComponent implements OnInit { + @Input() viewWidth: number = 0; + @Input() btnPosition: boolean = false; + + currentChannel: string = ''; + + constructor( + public channelService: ChannleService, + public toggleBoolean: ToggleBooleanService, + private router: ActivatedRoute, + public chatService: ChatService, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + + ngOnInit() { + this.routeUserId(); + } + + /** + * Opens the search bar by toggling a boolean value. + */ + openSearchbar() { + this.toggleBoolean.openSearchWindow = true; + } + + /** + * Closes the secondary chat window & sidebar. + */ + closeSecondaryChatAndSidebar() { + this.chatService.toggleSecondaryChat('none'); + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD) { + this.toggleBoolean.isSidebarOpen = false; + } + } + + /** + * Retrieves the user ID from the route parameters. + */ + routeUserId() { + if (this.router.params.subscribe()) { + this.router.params.subscribe((params) => { + this.currentChannel = params['id']; + }); + } + } +} diff --git a/src/app/highlight.pipe.spec.ts b/src/app/highlight.pipe.spec.ts new file mode 100644 index 0000000..f64cac0 --- /dev/null +++ b/src/app/highlight.pipe.spec.ts @@ -0,0 +1,8 @@ +import { HighlightPipe } from './highlight.pipe'; + +describe('HighlightPipe', () => { + it('create an instance', () => { + const pipe = new HighlightPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/highlight.pipe.ts b/src/app/highlight.pipe.ts new file mode 100644 index 0000000..0b7d585 --- /dev/null +++ b/src/app/highlight.pipe.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'highlight', + standalone: true, +}) +export class HighlightPipe implements PipeTransform { + /** + * Transforms the input text by highlighting matches of the search query. + * @param wholeText The entire text where matches will be highlighted. + * @param inputValue The search query to highlight. + * @returns The transformed text with highlighted matches. + */ + transform(wholeText: string, inputValue: string): string { + if (!inputValue) { + return wholeText; + } + const escapedInputValue = inputValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const re = new RegExp(escapedInputValue, 'gi'); + return wholeText.replace(re, '$&'); + } +} diff --git a/src/app/interface/channel.interface.ts b/src/app/interface/channel.interface.ts new file mode 100644 index 0000000..16a676a --- /dev/null +++ b/src/app/interface/channel.interface.ts @@ -0,0 +1,20 @@ +export const publicChannels: string[] = [ + 'ktoVhTjif9OndCsLfEF7', + 't0zOHsjKzq0uYSqsMx8j', +]; +export interface Channel { + id?: string; + name: string; + description: string; + creator: string; + privatChannel: boolean; + hashtag: string; + createdDate: string; + addedUser: Array; +} + +export interface PrvChannel { + id?: string; + creatorId: string; + talkToUserId: string; +} diff --git a/src/app/interface/chat.interface.ts b/src/app/interface/chat.interface.ts new file mode 100644 index 0000000..c679387 --- /dev/null +++ b/src/app/interface/chat.interface.ts @@ -0,0 +1,33 @@ +export interface Chat { + id: string; + userId: string; + channelId: string; + message: string; + edited: boolean; + publishedTimestamp: number; +} + +export interface ChatAnswers { + id: string; + chatId: string; + message: string; + edited: boolean; + publishedTimestamp: number; + userId: string; +} + +export interface ChatReactions { + id?: string; + chatId: string; + icon: string; + userId: string[]; +} + +export interface MessageData { + message: string; + publishedTimestamp: number; + userId: string; + channelId?: string; + chatId?: string; + edited: boolean; +} diff --git a/src/app/interface/user.interface.ts b/src/app/interface/user.interface.ts new file mode 100644 index 0000000..8c39df4 --- /dev/null +++ b/src/app/interface/user.interface.ts @@ -0,0 +1,9 @@ +export interface User { + id?: string; + uid:string; + firstName: string; + lastName: string; + avatar: string; + email:string; + status:boolean; +} diff --git a/src/app/service/channle.service.ts b/src/app/service/channle.service.ts new file mode 100644 index 0000000..6ddeabd --- /dev/null +++ b/src/app/service/channle.service.ts @@ -0,0 +1,163 @@ +import { Injectable, OnDestroy, inject } from '@angular/core'; +import { + Firestore, + addDoc, + collection, + doc, + onSnapshot, + updateDoc, +} from '@angular/fire/firestore'; +import { + publicChannels, + Channel, + PrvChannel, +} from '../interface/channel.interface'; +import { ChatService } from './chat.service'; + +@Injectable({ + providedIn: 'root', +}) +export class ChannleService implements OnDestroy { + firestore: Firestore = inject(Firestore); + + allChannels: Channel[] = []; + publicChannels: string[] = publicChannels; + showAddChannelBox: boolean = false; + btnIsValid: boolean = false; + saveEditBtnIsValid: boolean = false; + openPrvChat: boolean = false; + allPrvChannels: PrvChannel[] = []; + channelMembers: string[] = []; + loggedInUser: string = ''; + getChannelID: string = ''; + + unsubChannel; + unsubPrvChannel; + + constructor(private chatService: ChatService) { + this.unsubChannel = this.subChannelList(); + this.unsubPrvChannel = this.subPrvChannelList(); + } + + /** + * Construct Firestore path for a given collection. + * @param path Path of the collection in Firestore. + * @returns Firestore collection reference. + */ + firesorePath(path: string) { + return collection(this.firestore, path); + } + + /** + * Subscribe to the list of public channels in Firestore. + * @returns Unsubscribe function. + */ + subChannelList() { + return onSnapshot(this.firesorePath('channels'), (list) => { + this.allChannels = []; + list.forEach((element) => { + const channelWithId = { id: element.id, ...element.data() } as Channel; + this.allChannels.push(channelWithId); + }); + }); + } + + /** + * Subscribe to the list of public channels in Firestore. + * @returns Unsubscribe function. + */ + subPrvChannelList() { + return onSnapshot(this.firesorePath('prv-channels'), (list) => { + this.allPrvChannels = []; + list.forEach((element) => { + const channelWithId = { + id: element.id, + ...element.data(), + } as PrvChannel; + this.allPrvChannels.push(channelWithId); + }); + }); + } + + /** + * Update name or description of a channel in Firestore. + * @param category Collection category (e.g., 'channels' or 'prv-channels'). + * @param channelID ID of the channel to update. + * @param channelCategory Category to update ('name' or 'description'). + * @param textValue New value for the category. + */ + async saveAddedNameOrDescription( + category: string, + channelID: string, + channelCategory: string, + textValue: string + ) { + const docRef = doc(this.firestore, `${category}/${channelID}`); + await updateDoc(docRef, { [channelCategory]: textValue }); + } + + /** + * Create a new channel or private channel in Firestore. + * @param newChannel Channel or private channel object to create. + * @param path Path of the collection in Firestore. + * @returns ID of the newly created channel or undefined if creation fails. + */ + async createNewChannel( + newChannel: Channel | PrvChannel, + path: string + ): Promise { + try { + const docRef = await addDoc(this.firesorePath(path), newChannel); + this.chatService.getPrvChatId = docRef.id; + return docRef.id; + } catch (err) { + console.error('Error creating channel:', err); + return undefined; + } + } + + /** + * Add new member(s) to a channel in Firestore. + * @param category Collection category (e.g., 'channels' or 'prv-channels'). + * @param channelID ID of the channel to update. + * @param selectedUsers Array of user IDs to add as members. + * @param checkCategory Category to check ('addUserToChannel'). + */ + async addNewMemberToChannel( + category: string, + channelID: string, + selectedUsers: string[], + checkCategory: string + ) { + const currentChannelUsers = this.allChannels.filter( + (channel) => channel.id === channelID + ); + if (checkCategory === 'addUserToChannel') { + const allMembers: string[] = [ + ...selectedUsers, + ...currentChannelUsers[0].addedUser, + ]; + const docRef = doc(this.firestore, `${category}/${channelID}`); + await updateDoc(docRef, { addedUser: allMembers }); + } else if (checkCategory === 'leaveChannel') { + const docRef = doc(this.firestore, `${category}/${channelID}`); + await updateDoc(docRef, { addedUser: selectedUsers }); + } + } + + /** + * Clean up subscriptions when the service is destroyed. + */ + ngOnDestroy() { + this.unsubChannel(); + this.unsubPrvChannel(); + } + + /** + * Placeholder function for committing a batch of Firestore writes. + * @param batch Firestore batch object. + */ + commitBatch(batch: any) { + throw new Error('Function not implemented.'); + } +} diff --git a/src/app/service/chat.service.ts b/src/app/service/chat.service.ts new file mode 100644 index 0000000..a50b80d --- /dev/null +++ b/src/app/service/chat.service.ts @@ -0,0 +1,192 @@ +import { Injectable, OnDestroy, inject } from '@angular/core'; +import { + Firestore, + addDoc, + collection, + deleteDoc, + doc, + onSnapshot, + orderBy, + query, + updateDoc, +} from '@angular/fire/firestore'; +import { Chat, ChatAnswers, ChatReactions } from '../interface/chat.interface'; + +@Injectable({ + providedIn: 'root', +}) +export class ChatService implements OnDestroy { + firestore: Firestore = inject(Firestore); + + allChats: Chat[] = []; + allChatAnswers: ChatAnswers[] = []; + allChatReactions: ChatReactions[] = []; + isSecondaryChatId: string = ''; + isSecondaryChatOpen: boolean = false; + getChannelId: string = ''; + getPrvChatId: string = ''; + inputValue: string = ''; + + unsubChat; + unsubChatAnswers; + unsubChatReactions; + + constructor() { + this.unsubChat = this.subChatList(); + this.unsubChatAnswers = this.subChatAnswersList(); + this.unsubChatReactions = this.subChatListReactions(); + } + + + /** + * Subscribes to the chat list collection in Firestore and updates the local chat list accordingly. + * @returns A function to unsubscribe from the chat list. + */ + subChatList() { + const queryRef = query( + collection(this.firestore, 'chats'), + orderBy('publishedTimestamp') + ); + + return onSnapshot(queryRef, (list) => { + this.allChats = []; + list.forEach((element) => { + const chatWithId = { id: element.id, ...element.data() } as Chat; + this.allChats.push(chatWithId); + }); + }); + } + + + /** + * Subscribes to the chat answers list collection in Firestore and updates the local chat answers list accordingly. + * @returns A function to unsubscribe from the chat answers list. + */ + subChatAnswersList() { + return onSnapshot(collection(this.firestore, 'chat-answers'), (list) => { + this.allChatAnswers = []; + list.forEach((element) => { + const chatWithId = { id: element.id, ...element.data() } as ChatAnswers; + this.allChatAnswers.push(chatWithId); + }); + }); + } + + + /** + * Subscribes to the chat reactions list collection in Firestore and updates the local chat reactions list accordingly. + * @returns A function to unsubscribe from the chat reactions list. + */ + subChatListReactions() { + return onSnapshot(collection(this.firestore, 'reactions'), (list) => { + this.allChatReactions = []; + list.forEach((element) => { + const chatReactionsWithId = { + id: element.id, + ...element.data(), + } as ChatReactions; + this.allChatReactions.push(chatReactionsWithId); + }); + }); + } + + + /** + * Updates the specified chat document with the provided data. + * @param chatId The ID of the chat document to update. + * @param update The partial data to update the chat document with. + */ + async updateChat(chatId: string, update: Partial) { + const chatRef = doc(collection(this.firestore, 'chats'), chatId); + const updatedData = { ...update, edited: true }; + await updateDoc(chatRef, updatedData).catch((err) => { + console.error(err); + throw err; + }); + } + + + /** + * Updates the reaction document with the specified ID with the provided array of user IDs. + * @param reactionId The ID of the reaction document to update. + * @param array The array of user IDs to update the reaction with. + */ + async updateReaction(reactionId: any, array: string[]) { + await updateDoc(doc(collection(this.firestore, 'reactions'), reactionId), { + userId: array, + }).catch((err) => { + console.error(err); + }); + } + + + /** + * Creates a new reaction document with the provided data. + * @param reaction The reaction data to add to Firestore. + */ + async createNewReaction(reaction: ChatReactions) { + await addDoc(collection(this.firestore, 'reactions'), reaction).catch( + (err) => { + console.error(err); + } + ); + } + + + /** + * Deletes a document from the specified Firestore collection. + * @param docId The ID of the document to delete. + * @param database The name of the Firestore collection. + */ + async deleteData(docId: string, database: string) { + await deleteDoc(doc(collection(this.firestore, database), docId)).catch( + (err) => { + console.error(err); + } + ); + } + + + /** + * Retrieves chat answers associated with the specified chat ID. + * @param chatId The ID of the chat to retrieve answers for. + * @returns An array of chat answers. + */ + getChatAnswers(chatId: string): ChatAnswers[] { + const filteredTasks = this.allChatAnswers.filter( + (chat) => chat.chatId == chatId + ); + return filteredTasks; + } + + + /** + * Toggles the secondary chat window based on the provided chat ID. + * @param chatId The ID of the chat to toggle the secondary window for. + */ + toggleSecondaryChat(chatId: string) { + if (this.isSecondaryChatId == chatId) { + chatId = 'none'; + } + if (chatId == 'none') { + this.isSecondaryChatOpen = false; + this.isSecondaryChatId = ''; + } else { + this.isSecondaryChatOpen = true; + } + + if (this.isSecondaryChatOpen) { + this.isSecondaryChatId = chatId; + } + } + + + /** + * Unsubscribes from all Firestore subscriptions when the service is destroyed. + */ + ngOnDestroy() { + this.unsubChat(); + this.unsubChatAnswers(); + this.unsubChatReactions(); + } +} diff --git a/src/app/service/download-files.service.ts b/src/app/service/download-files.service.ts new file mode 100644 index 0000000..016c791 --- /dev/null +++ b/src/app/service/download-files.service.ts @@ -0,0 +1,65 @@ +import { Injectable, Input, OnInit } from '@angular/core'; +import { + getDownloadURL, + getStorage, + listAll, + ref, + uploadBytes, +} from '@angular/fire/storage'; +import { BehaviorSubject } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class DownloadFilesService { + uploadFiles: File[] = []; + downloadedFiles: BehaviorSubject<{ id: string; files: string[] }[]> = + new BehaviorSubject<{ id: string; files: string[] }[]>([]); + + fileNames: any[] = []; + + constructor() { + this.listAllFiles(); + } + + loadAllFiles(docID: string) { + // lädt die fails in den firebase storage + const storage = getStorage(); + for (const file of this.uploadFiles) { + const storageRef = ref(storage, `chatFiles/${docID}/${file.name}`); + uploadBytes(storageRef, file).then((snapshot) => { + this.listAllFiles(); + }); + } + } + + listAllFiles() { + const storage = getStorage(); + const listRef2 = ref(storage, 'chatFiles'); + + listAll(listRef2) + .then(async (res) => { + const downloadedFilesData: { id: string; files: string[] }[] = []; + + for (const folderRef of res.prefixes) { + const folderID = folderRef.name; + const folderFiles = []; + + const folderRes = await listAll(folderRef); + + for (const fileRef of folderRes.items) { + const url = await getDownloadURL(fileRef); + folderFiles.push(url); + } + + downloadedFilesData.push({ id: folderID, files: folderFiles }); + } + + // Emit the updated value + this.downloadedFiles.next(downloadedFilesData); + }) + .catch((error) => { + console.error('Fehler beim Abrufen der Dateien:', error); + }); + } +} diff --git a/src/app/service/language.service.ts b/src/app/service/language.service.ts new file mode 100644 index 0000000..e491b1d --- /dev/null +++ b/src/app/service/language.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable({ + providedIn: 'root', +}) +export class LanguageService { + currentLang = 'en'; + + constructor(private translate: TranslateService) { + this.translate.setDefaultLang(this.currentLang); + } + + + /** + * Switches the application's current language. + * + * This method sets the current language based on the specified `lang` parameter and updates the translation service to use the new language. This is useful for enabling runtime language switching in a multi-lingual application. + * + * @param lang The language code to switch to. Supported values are 'en' for English and 'de' for German. + */ + switchLanguage() { + this.currentLang = this.currentLang === 'en' ? 'de' : 'en'; + this.translate.use(this.currentLang); + } +} diff --git a/src/app/service/login.service.ts b/src/app/service/login.service.ts new file mode 100644 index 0000000..6dd06f5 --- /dev/null +++ b/src/app/service/login.service.ts @@ -0,0 +1,390 @@ +import { Injectable, inject } from '@angular/core'; +import { + Firestore, + QuerySnapshot, + addDoc, + arrayUnion, + collection, + doc, + getDocs, + query, + updateDoc, + where, +} from '@angular/fire/firestore'; +// import { User } from '../interface/user.interface'; +import { + getAuth, + signInWithPopup, + GoogleAuthProvider, + signInWithEmailAndPassword, + createUserWithEmailAndPassword, +} from 'firebase/auth'; +import { Router } from '@angular/router'; +import { User } from '../interface/user.interface'; +import { UserService } from './user.service'; +import { publicChannels } from '../interface/channel.interface'; +// import { User } from 'firebase/auth'; + +@Injectable({ + providedIn: 'root', +}) +export class loginService { + firestore: Firestore = inject(Firestore); + email: string = ''; + password: string = ''; + name: string = ''; + firstName: string = ''; + lastName: string = ''; + avatar: string = './assets/img/user-icons/guest.svg'; + currentUser: string = ''; + errorMessage: string = ''; + isFirstLoad: boolean = true; + passwordFieldType: string = 'password'; + passwordIcon: string = './assets/img/login/close-eye.svg'; + private hasAnimationPlayed = false; + private introCompleteStatus = false; + + constructor(private router: Router, private userService: UserService) { + this.ifUserLoggedIn(); + } + + /** + * Checks if a user is logged in by checking if there is a user stored in the local storage. + * If a user is found, it redirects to the main page. + * @returns {void} + */ + ifUserLoggedIn() { + let currentUser = localStorage.getItem('currentUserDABubble'); + if (currentUser !== null) { + this.router.navigate([`/main`]); + } + } + + // -------------------- login start -------------------------------> + + /** + * Authenticates a user using their email and password, fetches the user document, and handles errors. + */ + login() { + const auth = getAuth(); + signInWithEmailAndPassword(auth, this.email, this.password) + .then((userCredential) => { + const user = userCredential.user; + const usersCollection = collection(this.firestore, 'users'); + const querySnapshot = query( + usersCollection, + where('uid', '==', user.uid) + ); + getDocs(querySnapshot) + .then((snapshot) => this.userDocument(snapshot)) + .catch((error) => { + console.error('Fehler beim Abrufen des Benutzerdokuments:', error); + }); + }) + .catch((error) => { + const errorCode = error.code; + this.switchCase(errorCode); + }); + } + + /** + * Processes the query snapshot to fetch user document data and updates local and session state. + * @param snapshot QuerySnapshot object containing user documents. + */ + userDocument(snapshot: QuerySnapshot) { + if (snapshot.docs.length > 0) { + const userDoc = snapshot.docs[0]; + this.currentUser = userDoc.id; + this.getUserIdInLocalStorage(this.currentUser); + this.email = ''; + this.password = ''; + } else { + console.error('Kein zugehöriges Benutzerdokument gefunden.'); + } + } + + /** + * Handles error codes returned from login attempts and sets appropriate error messages. + * @param errorCode String representing the error code returned from Firebase authentication. + */ + switchCase(errorCode: string) { + switch (errorCode) { + case 'auth/invalid-credential': + this.errorMessage = + '*Ungültige Anmeldeinformationen. Bitte überprüfen Sie Ihre Eingaben.'; + break; + case 'auth/too-many-requests': + this.errorMessage = + '*Der Zugriff auf dieses Konto wurde aufgrund zahlreicher fehlgeschlagener Anmeldeversuche vorübergehend deaktiviert.'; + break; + default: + this.errorMessage = '*Bitte Überprüfe deine Eingaben.'; + break; + } + } + + /** + * Performs a guest login using predetermined credentials and updates the user's online status. + */ + guestLogin() { + const auth = getAuth(); + const email = 'guest@guestaccount.com'; + const password = 'guest@guestaccount.com'; + const userId = 'BSUUclnjovMeE3v85Hmy'; + this.email = 'guest@guestaccount.com'; + this.password = 'guest@guestaccount.com'; + + signInWithEmailAndPassword(auth, email, password) + .then(() => { + this.getUserIdInLocalStorage(userId); + this.email = ''; + this.password = ''; + }) + .catch((error) => { + console.error(error); + this.errorMessage = + 'Fehler bei der Gastanmeldung. Bitte versuchen Sie es später erneut.'; + }); + } + + // -------------------- register -------------------------------> + + /** + * Registers a new user with Firebase authentication and stores user data in Firestore. + */ + register() { + const auth = getAuth(); + createUserWithEmailAndPassword(auth, this.email, this.password) + .then((userCredential) => { + const user = userCredential.user; + + const userDataToSave: User = { + uid: user.uid, + firstName: this.firstName, + lastName: this.lastName, + avatar: this.avatar, + email: this.email, + status: true, + }; + + this.createUserInFirestore(userDataToSave); + this.deleteUserFormData(); + }) + .catch((error) => { + console.error(error); + this.deleteUserFormData(); + }); + } + + /** + * Saves user data to Firestore and updates the application state. + * @param user The user object containing information to be saved. + */ + async createUserInFirestore(user: User) { + const userDataToSave: User = { + uid: user.uid, + email: user.email, + firstName: user.firstName || '', + lastName: user.lastName || '', + avatar: user.avatar || './assets/img/user-icons/guest.svg', + status: true, + }; + const usersCollection = collection(this.firestore, 'users'); + try { + const docRef = await addDoc(usersCollection, userDataToSave); + this.currentUser = docRef.id; + await this.addUserToChannels(this.currentUser, publicChannels); + await this.addPrivateChannel(this.currentUser); + this.getUserIdInLocalStorage(this.currentUser); + this.email = ''; + this.password = ''; + } catch (error) { + console.error(error); + } + } + + // -------------------- choose avatar -------------------------------> + + /** + * Gets the URL of the avatar and updates the avatar source. + * @param url String URL of the avatar. + * @return Updated avatar URL. + */ + getAvatarUrl(url: string) { + return (this.avatar = url); + } + + // -------------------- animation login -------------------------------> + + /** + * Retrieves the animation state indicating whether it has played. + * @returns {boolean} True if the animation has already played, false otherwise. + */ + getAnimationState(): boolean { + return this.hasAnimationPlayed; + } + + /** + * Retrieves the completion status of the introduction class. + * @returns {boolean} True if the introduction is complete, false otherwise. + */ + getFinalclass(): boolean { + return this.introCompleteStatus; + } + + /** + * Sets the animation state. + * @param {boolean} state - The new state of the animation. + */ + setAnimationState(state: boolean): void { + this.hasAnimationPlayed = state; + } + + /** + * Sets the final class completion status. + * @param {boolean} state - The new completion status of the introduction. + */ + setFinalClass(state: boolean): void { + this.introCompleteStatus = state; + } + + // -------------------- GoogleLogin -------------------------------> + + /** + * Handles the user's sign-in process via Google authentication. + * Invokes Firebase's signInWithPopup to authenticate and potentially creates or updates the user's data in Firestore. + */ + googleLogin() { + const auth = getAuth(); + const provider = new GoogleAuthProvider(); + + signInWithPopup(auth, provider) + .then((result) => { + const user = result.user; + const usersCollection = collection(this.firestore, 'users'); + const querySnapshot = query( + usersCollection, + where('uid', '==', user.uid) + ); + getDocs(querySnapshot).then((snapshot) => { + if (snapshot.empty) { + this.createUserInFirestore({ + uid: user.uid, + email: user.email || 'leer@gmail.com', + firstName: user.displayName + ? user.displayName.split(' ')[0] + : 'FirstName', + lastName: user.displayName + ? user.displayName.split(' ').slice(1).join(' ') + : 'LastName', + avatar: user.photoURL || './assets/img/user-icons/guest.svg', + status: true, + }); + } else { + this.ifExistUser(snapshot); + } + }); + }) + .catch((error) => { + console.error(error); + }); + } + + /** + * Processes existing user data after successful Google login. + * @param {QuerySnapshot} snapshot - Firestore snapshot containing the user's data. + */ + ifExistUser(snapshot: QuerySnapshot) { + this.currentUser = snapshot.docs[0].id; + this.getUserIdInLocalStorage(this.currentUser); + } + + // -------------------- UserAddFunktions -------------------------------> + + /** + * Updates the online status of the user in Firestore. + * @param userId The user's document ID in Firestore. + */ + async updateUserOnlineStatus(userId: string) { + const userDocRef = doc(this.firestore, 'users', userId); + const updates = { + status: true, + }; + await updateDoc(userDocRef, updates) + .then(() => { + console.error(); + }) + .catch((error) => { + console.error(error); + }); + } + + /** + * Adds the current user to specified channels in Firestore. It updates each channel document + * to include the user's ID in an array of added users, ensuring that the user is part of the channel. + * Each operation is performed independently, and errors are handled individually. + * + * @param {string} currentUser - The ID of the user to be added to the channels. + * @param {string[]} channelIds - An array of channel IDs to which the user will be added. + */ + addUserToChannels(currentUser: string, channelIds: string[]) { + channelIds.forEach((channelId) => { + const channelDocRef = doc(this.firestore, 'channels', channelId); + + updateDoc(channelDocRef, { + addedUser: arrayUnion(currentUser), + }).catch((error) => { + console.error(error); + }); + }); + } + + /** + * Asynchronously adds a private channel for the current user. + * + * This method creates a new document in the 'prv-channels' collection within Firestore. The new document contains the creator's user ID for both the creator and recipient fields, implying a private or personal channel. + * + * @param currentUser The user ID of the current user and the creator of the private channel. + * @async + * @returns {Promise} A promise that resolves when the channel is successfully added or rejects with an error message if the operation fails. + */ + async addPrivateChannel(currentUser: string) { + try { + await addDoc(collection(this.firestore, 'prv-channels'), { + creatorId: currentUser, + talkToUserId: currentUser, + }); + } catch (error) { + console.error('Fehler beim Erstellen des privaten Kanals: ', error); + } + } + + /** + * Stores the current user's ID in the local storage. + * @param {string} userId - The ID of the current user to be stored. + */ + async getUserIdInLocalStorage(userId: string) { + localStorage.setItem('currentUserDABubble', JSON.stringify(userId)); + await this.updateUserOnlineStatus(userId); + window.location.reload(); + } + + deleteUserFormData() { + this.name = ''; + this.email = ''; + this.password = ''; + } + + togglePasswordVisibility() { + this.passwordFieldType = + this.passwordFieldType === 'password' ? 'text' : 'password'; + this.toggleIcon(); + } + + toggleIcon() { + this.passwordIcon = + this.passwordIcon === './assets/img/login/close-eye.svg' + ? './assets/img/login/open-eye.svg' + : './assets/img/login/close-eye.svg'; + } +} diff --git a/src/app/service/overlay.service.ts b/src/app/service/overlay.service.ts new file mode 100644 index 0000000..9e021d4 --- /dev/null +++ b/src/app/service/overlay.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class OverlayService { + private overlayDataSubject = new BehaviorSubject(null); + overlayData$ = this.overlayDataSubject.asObservable(); + + constructor() {} + + setOverlayData(data: any) { + this.overlayDataSubject.next(data); + } +} diff --git a/src/app/service/shared.service.ts b/src/app/service/shared.service.ts new file mode 100644 index 0000000..ce85102 --- /dev/null +++ b/src/app/service/shared.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class SharedService { + // Responsive design: + RESPONSIVE_THRESHOLD_MOBILE: number = 600; + RESPONSIVE_THRESHOLD: number = 1300; + RESPONSIVE_THRESHOLD_MAX: number = 1900; + RESPONSIVE_THRESHOLD_SEARCHBAR: number = 1100; +} diff --git a/src/app/service/toggle-boolean.service.ts b/src/app/service/toggle-boolean.service.ts new file mode 100644 index 0000000..a3f1823 --- /dev/null +++ b/src/app/service/toggle-boolean.service.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; + + +@Injectable({ + providedIn: 'root' +}) +export class ToggleBooleanService { + + constructor() { } + + openSearchWindow: boolean = false; + openChannelMemberWindow: boolean = false; + closeChannelMemberWindow: boolean = false; + openSearchWindowHead: boolean = false; + selectUserInMsgBox:boolean = false; + isSidebarOpen: boolean = true; + + /** + * Opens or closes the add member window based on the provided boolean value. + * @param boolean A boolean value to determine whether to open or close the add member window. + */ + openAddMemberWindow(boolean : boolean){ + this.closeChannelMemberWindow = boolean; + } +} diff --git a/src/app/service/user.service.ts b/src/app/service/user.service.ts new file mode 100644 index 0000000..ff30b62 --- /dev/null +++ b/src/app/service/user.service.ts @@ -0,0 +1,174 @@ +import { Injectable, OnDestroy, inject } from '@angular/core'; +import { + Firestore, + collection, + doc, + onSnapshot, + updateDoc, +} from '@angular/fire/firestore'; +import { User } from '../interface/user.interface'; +import { ChannleService } from './channle.service'; +import { getAuth, signOut } from 'firebase/auth'; +import { Router } from '@angular/router'; + +@Injectable({ + providedIn: 'root', +}) +export class UserService implements OnDestroy { + firestore: Firestore = inject(Firestore); + nameValue: string = ''; + emailValue: string = ''; + allUsers: User[] = []; + getUserIDs: string[] = []; + getFiltertUsers: User[] = []; + isUserLogin: boolean = true; + + unsubUser; + + constructor(private channelService: ChannleService, private route: Router) { + this.unsubUser = this.subUserList(); + } + + /** + * Retrieves the current user's ID from local storage. + * @returns {string|number|undefined} The ID of the current user if found in local storage, otherwise undefined. + */ + getCurrentUserId() { + let currentUser = localStorage.getItem('currentUserDABubble'); + if (currentUser !== null) { + return JSON.parse(currentUser); + } + } + + /** + * Subscribe to the list of users in Firestore. + * @returns Unsubscribe function. + */ + subUserList() { + return onSnapshot(collection(this.firestore, 'users'), (list) => { + this.allUsers = []; + this.getUserIDs = []; + list.forEach((element) => { + const userWithId = { id: element.id, ...element.data() } as User; + this.allUsers.push(userWithId); + this.getUserIDs.push(userWithId.id!); + }); + }); + } + + /** + * Get all users. + * @returns Array of User objects. + */ + getUsers(): User[] { + return this.allUsers; + } + + /** + * Get current user's data. + * @returns Array containing current user's data. + */ + getCurentUsers() { + const filteredUser = this.getUsers().filter( + (user) => user.id == this.getCurrentUserId() + ); + this.nameValue = + filteredUser[0]?.firstName + ' ' + filteredUser[0]?.lastName; + this.emailValue = filteredUser[0]?.email; + return filteredUser; + } + + /** + * Create a private channel between the current user and another user. + * @param filterUserID ID of the user to create the private channel with. + * @returns Existing private channel if it already exists, otherwise an empty string. + */ + createPrvChannel(filterUserID: string) { + const newPrvChannel = { + creatorId: this.getCurrentUserId(), + talkToUserId: filterUserID, + }; + + const channelExistsBoolean = this.channelService.allPrvChannels.some( + (channel) => + (channel.creatorId === newPrvChannel.creatorId && + channel.talkToUserId === newPrvChannel.talkToUserId) || + (channel.creatorId === newPrvChannel.talkToUserId && + channel.talkToUserId === newPrvChannel.creatorId) + ); + if (!channelExistsBoolean) { + const docId = this.channelService.createNewChannel( + newPrvChannel, + 'prv-channels' + ); + return docId; + } + return ''; + } + + /** + * Update current user's data in Firestore. + * @param newFirstName New first name. + * @param newLastName New last name. + * @param newEmail New email. + */ + updateUserData(newFirstName: string, newLastName: string, newEmail: string) { + const userDocRef = doc(this.firestore, 'users', this.getCurrentUserId()); + const updates: any = {}; + + if (newEmail !== '') { + updates.email = newEmail; + } + if (newFirstName !== '') { + updates.firstName = newFirstName; + updates.lastName = newLastName; + } + + updateDoc(userDocRef, updates).catch((error) => { + console.error(error); + }); + } + + /** + * Log out the current user. + */ + currentUserLogout() { + const auth = getAuth(); + const userId = this.getCurrentUserId(); + + if (userId) { + const userDocRef = doc(this.firestore, `users/${userId}`); + + updateDoc(userDocRef, { status: false }) + .then(() => { + signOut(auth) + .then(() => { + this.deleteUserIdInLocalStorage(); + this.route.navigate(['/login']); + }) + .catch((error) => { + console.error(error); + }); + }) + .catch((error) => { + console.error(error); + }); + } else { + console.error('Keine UserID gefunden'); + } + } + + /** + * Deletes the user ID from local storage. + */ + deleteUserIdInLocalStorage() { + localStorage.removeItem('currentUserDABubble'); + } + + /** + * Clean up subscriptions when the service is destroyed. + */ + ngOnDestroy() { + this.unsubUser(); + } +} diff --git a/src/app/shared/components/emoji-picker/emoji-picker.component.html b/src/app/shared/components/emoji-picker/emoji-picker.component.html new file mode 100644 index 0000000..770dcdf --- /dev/null +++ b/src/app/shared/components/emoji-picker/emoji-picker.component.html @@ -0,0 +1,7 @@ + diff --git a/src/app/shared/components/emoji-picker/emoji-picker.component.scss b/src/app/shared/components/emoji-picker/emoji-picker.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/components/emoji-picker/emoji-picker.component.spec.ts b/src/app/shared/components/emoji-picker/emoji-picker.component.spec.ts new file mode 100644 index 0000000..c555cd5 --- /dev/null +++ b/src/app/shared/components/emoji-picker/emoji-picker.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EmojiPickerComponent } from './emoji-picker.component'; + +describe('EmojiPickerComponent', () => { + let component: EmojiPickerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [EmojiPickerComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(EmojiPickerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/emoji-picker/emoji-picker.component.ts b/src/app/shared/components/emoji-picker/emoji-picker.component.ts new file mode 100644 index 0000000..3dc604a --- /dev/null +++ b/src/app/shared/components/emoji-picker/emoji-picker.component.ts @@ -0,0 +1,35 @@ +import { Component, EventEmitter, Input, Output, output } from '@angular/core'; +import { PickerComponent } from '@ctrl/ngx-emoji-mart'; + +@Component({ + selector: 'app-emoji-picker', + standalone: true, + imports: [PickerComponent], + templateUrl: './emoji-picker.component.html', + styleUrl: './emoji-picker.component.scss', +}) +export class EmojiPickerComponent { + @Input() output: string = ''; + @Output() emojiOutputEmitter: EventEmitter = new EventEmitter(); + @Output() emojiVisibleEmitter: EventEmitter = + new EventEmitter(); + + + /** + * Adds an emoji. + * @param event The event object. + */ + addEmoji(event: any) { + this.output == 'id' ? this.emojiOutputEmitter.emit(event.emoji.id) : null; + this.output == 'native' + ? this.emojiOutputEmitter.emit(event.emoji.native) + : null; + this.closeEmojiPicker(); + } + + + /** Closes the emoji picker. */ + closeEmojiPicker() { + this.emojiVisibleEmitter.emit(false); + } +} diff --git a/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.html b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.html new file mode 100644 index 0000000..e3b7996 --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.html @@ -0,0 +1,109 @@ +
+@for(i of userService.getCurentUsers(); track i){ +
+
+
+

{{ "edit-user-details.profile" | translate }}

+ +
+ + + +
+
+
+ +

+ {{ "edit-user-details.fullName" | translate }} +

+
+ @if (!filterGuest()) { + + + } @else { + + } +
+ +
+
+ +

{{ "edit-user-details.email" | translate }}

+
+ @if (!filterGuest()) { + + + } @else { + + } +
+
+ +
+ + +
+ @if (asGuestOnline) { +

{{ "edit-user-details.errorMessage" | translate }}

+ } +
+
+} diff --git a/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.scss b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.scss new file mode 100644 index 0000000..b6329d4 --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.scss @@ -0,0 +1,194 @@ +@import "../../../../../../styles.scss"; + +.whiteBox { + width: 400px; + height: auto; + background-color: white; + border-radius: 35px; + position: absolute; + z-index: 5; + top: 110px; + right: 20px; + @include displayFlex(); + flex-direction: column; + padding: 24px; + .boxHeader { + width: 360px; + @include displayFlex($j: space-between); + } + .profileImg { + width: 200px; + height: 200px; + object-fit: cover; + border-radius: 50%; + margin: 56px; + } + p { + color: red; + margin-bottom: 16px; + } +} + +.inputBox { + width: calc(100% - 24px); + margin-bottom: 24px; + .positionName { + .positionNameIcon { + margin: 12px 0; + @include displayFlex($j: flex-start, $g: 20px); + p { + font-size: 21px; + font-weight: 600; + margin: 0; + color: #000; + } + } + .inputName { + width: calc(100% - 24px); + border: 1px solid #888dec; + outline: none; + height: 26px; + border-radius: 25px; + padding: 8px 12px; + margin-bottom: 12px; + font-size: 18px; + font-weight: 400; + transition: 0.3s ease-in-out; + &:hover { + border: 1px solid #2c36f0; + } + } + } +} + +.inputDisabled { + width: calc(100% - 24px); + border: none; + background-color: rgba(34, 34, 34, 0.2588235294); + outline: none; + height: 26px; + border-radius: 25px; + padding: 8px 12px; + margin-bottom: 12px; + font-size: 18px; + font-weight: 400; +} + +.position2Btn { + margin-bottom: 24px; + @include displayFlex($g: 26px); + .cancelBtn { + width: 120px; + height: 48px; + background-color: white; + border: 1px solid #888dec; + border-radius: 25px; + font-size: larger; + color: #444df2; + transition: 0.3s ease-in-out; + &:hover { + background-color: #444df2; + color: white; + cursor: pointer; + } + } + .saveBtn { + width: 120px; + height: 48px; + background-color: #444df2; + border: none; + border-radius: 25px; + font-size: larger; + color: white; + transition: 0.3s ease-in-out; + &:hover { + background-color: #888dec; + cursor: pointer; + } + } +} + +.grayBackground { + width: 100vw; + height: 100vh; + position: absolute; + top: 0; + left: 0; + z-index: 5; +} + +.disabledBtn { + background-color: #22222242; + border: none; + font-size: larger; + color: #fff; + width: 120px; + height: 48px; + border-radius: 25px; + font-size: larger; +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .whiteBox { + border-radius: 35px; + width: auto; + right: 22px; + height: auto; + top: unset; + right: 15vw; + left: 15vw; + padding: 24px; + .boxHeader { + width: 100%; + padding: 0 12px; + p { + font-size: 21px; + font-weight: 700; + } + } + .profileImg { + width: 120px; + height: 120px; + margin: 18px; + } + p { + font-size: 13px; + } + } + .detailsBox { + width: 100%; + padding: 0 12px; + .editBtnPosition { + .name { + font-size: 24px; + font-weight: 700; + } + } + } + + .emailBox { + @include displayFlex($j: flex-start, $a: flex-start, $g: 10px); + img { + margin-top: 2px; + } + .email { + > p { + font-size: 18px; + font-weight: 600; + margin-bottom: 10px; + } + > a { + margin-bottom: 0; + } + } + } +} + +@media screen and (max-width: 450px) { + .whiteBox { + right: 5vw; + left: 5vw; + } +} diff --git a/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.spec.ts b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.spec.ts new file mode 100644 index 0000000..04dd6cf --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditUserDetailsComponent } from './edit-user-details.component'; + +describe('EditUserDetailsComponent', () => { + let component: EditUserDetailsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [EditUserDetailsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(EditUserDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.ts b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.ts new file mode 100644 index 0000000..48b2a14 --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user-details/edit-user-details.component.ts @@ -0,0 +1,176 @@ +import { CommonModule } from '@angular/common'; +import { + Component, + ElementRef, + EventEmitter, + Input, + Output, + ViewChild, +} from '@angular/core'; +import { EditUserComponent } from '../edit-user.component'; +import { UserService } from '../../../../../service/user.service'; +import { FormsModule, NgForm } from '@angular/forms'; +import { ChannleService } from '../../../../../service/channle.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { SmallBtnComponent } from '../../../small-btn/small-btn.component'; + +@Component({ + selector: 'app-edit-user-details', + standalone: true, + imports: [ + CommonModule, + EditUserComponent, + FormsModule, + TranslateModule, + SmallBtnComponent, + ], + templateUrl: './edit-user-details.component.html', + styleUrl: './edit-user-details.component.scss', +}) +export class EditUserDetailsComponent { + asGuestOnline: boolean = false; + nameValueBoolean: boolean = false; + emailValueBoolean: boolean = false; + changedName: string = ''; + changedEmail: string = ''; + @Input() openEditUserValue!: boolean; + @Input() showCurrentProfile!: boolean; + @ViewChild('inputName') inputName!: ElementRef; + @ViewChild('inputEmail') inputEmail!: ElementRef; + + @Output() closeEditWindow = new EventEmitter(); + @Output() saveUserData = new EventEmitter(); + + constructor( + public userService: UserService, + public channelService: ChannleService + ) {} + + /** Filters whether the user is a guest. */ + filterGuest() { + const getGuest = this.userService.allUsers.filter( + (user) => user.id === this.userService.getCurrentUserId() + ); + if ('BSUUclnjovMeE3v85Hmy' === getGuest[0].id) { + this.asGuestOnline = true; + return false; + } else { + this.asGuestOnline = false; + return true; + } + } + + /** Closes the edit user window. */ + closeEditUserWindow() { + this.openEditUserValue = false; + this.closeEditWindow.emit(this.openEditUserValue); + this.channelService.saveEditBtnIsValid = false; + this.inputName.nativeElement.value = this.userService.nameValue; + this.inputEmail.nativeElement.value = this.userService.emailValue; + } + + /** Saves the new user data. */ + saveNewUserData(ngForm: NgForm) { + if (ngForm.submitted && ngForm.form.valid) { + if (this.channelService.saveEditBtnIsValid || this.emailValueBoolean) { + this.changeNameValue(); + const getName = this.splitNameValue(); + this.changeNameValue(); + this.userService.updateUserData( + getName[0], + getName[1], + this.changedEmail + ); + + this.showCurrentProfile = false; + this.channelService.saveEditBtnIsValid = false; + this.saveUserData.emit(this.showCurrentProfile); + } + } + } + + /** Get the name value. */ + changeNameValue() { + if (this.changedName == '') { + this.changedName = this.userService.nameValue; + } + } + + /**Separate the first ans lastname. */ + splitNameValue() { + const fullname: string[] = this.changedName.split(' '); + const newFirstName: string = fullname[0]; + let newLastName: string = fullname[1]; + if (fullname[2]) { + newLastName += ' ' + fullname[2]; + } + return [newFirstName, newLastName]; + } + + /** Get the email value. */ + chechEmailValue() { + if (this.changedEmail == '') { + this.changedEmail = this.userService.emailValue; + } + } + + /** + * Checks if the user name is valid. + * @param nameValue The value of the user's name. + */ + checkIfUserNameIsValid(nameValue: string) { + if (nameValue.trim() === '') { + this.nameValueBoolean = false; + } else { + const channelNameLenght = nameValue.length; + if (channelNameLenght >= 3) { + this.nameValueBoolean = true; + this.changedName = nameValue; + } else { + this.nameValueBoolean = false; + } + } + this.chackSaveBtnName(); + } + + /** + * Checks if the user email is valid. + * @param emailValue The value of the user's email. + */ + checkIfUserEmailIsValid(emailValue: string) { + if (emailValue.trim() === '') { + this.emailValueBoolean = false; + } else { + const emailRegex = /^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{2,}$/; + if (emailRegex.test(emailValue)) { + this.emailValueBoolean = true; + this.changedEmail = emailValue; + } else { + this.emailValueBoolean = false; + } + } + this.checkSaveBtnEmail(); + } + + /** + * Checks if the save button is valid. + */ + chackSaveBtnName() { + if (this.nameValueBoolean) { + this.channelService.saveEditBtnIsValid = true; + } else { + this.channelService.saveEditBtnIsValid = false; + } + } + + /** + * Checks if the save button is valid. + */ + checkSaveBtnEmail() { + if (this.nameValueBoolean) { + this.channelService.saveEditBtnIsValid = true; + } else { + this.channelService.saveEditBtnIsValid = false; + } + } +} diff --git a/src/app/shared/components/header/edit-user/edit-user.component.html b/src/app/shared/components/header/edit-user/edit-user.component.html new file mode 100644 index 0000000..bbdb46d --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user.component.html @@ -0,0 +1,55 @@ +
+@for(i of userService.getCurentUsers(); track i){ +
+
+

Profil

+ +
+ +
+
+

{{ i.firstName }} {{ i.lastName }}

+ +
+ +
+ + @if (i.status) { +

Aktiv

+ } @else { +

Offline

+ } +
+ +
+ + +
+
+
+} + + diff --git a/src/app/shared/components/header/edit-user/edit-user.component.scss b/src/app/shared/components/header/edit-user/edit-user.component.scss new file mode 100644 index 0000000..d1492d0 --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user.component.scss @@ -0,0 +1,192 @@ +@import "../../../../../styles.scss"; + +.grayBackground { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + @include displayFlex(); + z-index: 2; +} + +.whiteBox { + width: 400px; + height: auto; + background-color: white; + border-radius: 35px; + position: absolute; + z-index: 5; + top: 110px; + right: 20px; + @include displayFlex(); + flex-direction: column; + padding: 24px; + .boxHeader { + width: 360px; + @include displayFlex($j: space-between); + p { + font-size: 24px; + font-weight: 700; + } + } + .profileImg { + width: 200px; + height: 200px; + object-fit: cover; + border-radius: 50%; + margin: 56px; + } + > button { + @include displayFlex($g: 12px); + background-color: #444df2; + border: none; + border-radius: 25px; + padding: 12px; + padding-left: 22px; + padding-right: 22px; + font-size: larger; + font-weight: 500; + color: white; + margin: 32px; + cursor: pointer; + } +} + +.detailsBox { + width: 360px; + .editBtnPosition { + @include displayFlex($j: space-between); + margin-bottom: 20px; + .name { + font-size: 32px; + font-weight: 700; + } + .editBtn { + color: #535af1; + cursor: pointer; + &:hover { + font-weight: 600; + } + } + } + .statusBox { + @include displayFlex($j: flex-start, $g: 12px); + margin-bottom: 40px; + > p { + margin: 0; + font-size: medium; + font-weight: 500; + } + } +} + +.fontColorGreen { + color: #92c83e; +} + +.emailBox { + @include displayFlex($j: flex-start, $a: flex-start, $g: 20px); + height: 96px; + margin-top: 24px; + img { + width: 25px; + height: 20px; + margin-top: 3px; + } + .email { + > p { + font-size: 20px; + font-weight: 600; + margin-bottom: 20px; + } + > a { + color: #4ea1ff; + font-size: 16px; + text-decoration: none; + margin-bottom: 20px; + background: linear-gradient(currentColor 0 0) bottom left/ + var(--underline-width, 0%) 0.1em no-repeat; + display: inline-block; + transition: background-size 0.5s; + &:hover { + --underline-width: 100%; + } + } + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MAX) { + .arrowLeft { + display: block; + margin-left: 18px; + transition: 0.3 linear; + &:hover { + cursor: pointer; + scale: 1.2; + } + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .whiteBox { + border-radius: 35px; + width: auto; + right: 22px; + height: fit-content; + top: unset; + right: 15vw; + left: 15vw; + padding: 24px; + .boxHeader { + width: 100%; + padding: 0 12px; + p { + font-size: 21px; + font-weight: 700; + } + } + .profileImg { + width: 120px; + height: 120px; + margin: 18px; + } + } + .detailsBox { + width: 100%; + padding: 0 12px; + .editBtnPosition { + .name { + font-size: 24px; + font-weight: 700; + } + } + } + + .emailBox { + @include displayFlex($j: flex-start, $a: flex-start, $g: 10px); + img { + margin-top: 2px; + } + .email { + > p { + font-size: 18px; + font-weight: 600; + margin-bottom: 10px; + } + > a { + margin-bottom: 0; + } + } + } +} + +@media screen and (max-width: 450px) { + .whiteBox { + right: 5vw; + left: 5vw; + } +} diff --git a/src/app/shared/components/header/edit-user/edit-user.component.spec.ts b/src/app/shared/components/header/edit-user/edit-user.component.spec.ts new file mode 100644 index 0000000..d38a16c --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditUserComponent } from './edit-user.component'; + +describe('EditUserComponent', () => { + let component: EditUserComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [EditUserComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(EditUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/header/edit-user/edit-user.component.ts b/src/app/shared/components/header/edit-user/edit-user.component.ts new file mode 100644 index 0000000..4158c1b --- /dev/null +++ b/src/app/shared/components/header/edit-user/edit-user.component.ts @@ -0,0 +1,55 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { EditUserDetailsComponent } from './edit-user-details/edit-user-details.component'; +import { UserService } from '../../../../service/user.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { SmallBtnComponent } from '../../small-btn/small-btn.component'; + +@Component({ + selector: 'app-edit-user', + standalone: true, + imports: [ + CommonModule, + EditUserDetailsComponent, + TranslateModule, + SmallBtnComponent, + ], + templateUrl: './edit-user.component.html', + styleUrl: './edit-user.component.scss', +}) +export class EditUserComponent { + isOnline = true; + openProfil = false; + openEditUserValue = false; + @Input() showCurrentProfile!: boolean; + + @Output() testValueChange = new EventEmitter(); + + constructor(public userService: UserService) {} + + /** Toggles the side menu. */ + showSideMenu() { + this.openEditUserValue = !this.openEditUserValue; + } + + /** Opens the edit user section. */ + openEditUser() { + this.openEditUserValue = true; + } + + /** Closes the current profile. */ + closeCurrentProfile() { + this.showCurrentProfile = false; + this.testValueChange.emit(this.showCurrentProfile); + this.openEditUserValue = false; + } + + /** + * Updates the close value. + * @param value The value to update. + */ + updateCloseValue(value: boolean) { + this.showCurrentProfile = value; + this.openEditUserValue = value; + } +} diff --git a/src/app/shared/components/header/header.component.html b/src/app/shared/components/header/header.component.html new file mode 100644 index 0000000..1d99c93 --- /dev/null +++ b/src/app/shared/components/header/header.component.html @@ -0,0 +1,65 @@ +
+
+ @if (viewWidth <= RESPONSIVE_THRESHOLD && !this.toggleBoolean.isSidebarOpen) + { + + } @else { + + } +
+
+ +
+
+
+ @for(i of userService.getCurentUsers(); track i){ +

{{ i.firstName }} {{ i.lastName }}

+ +
+ + +
+ } + +
+
+
+ + + + diff --git a/src/app/shared/components/header/header.component.scss b/src/app/shared/components/header/header.component.scss new file mode 100644 index 0000000..1b2d807 --- /dev/null +++ b/src/app/shared/components/header/header.component.scss @@ -0,0 +1,217 @@ +@import "../../../../styles.scss"; + +header { + height: 100%; + @include displayFlex($j: space-between); +} + +.logo { + display: flex; + justify-content: left; + align-items: center; + max-width: fit-content; + transition: 0.3 linear; + cursor: pointer; + img { + &:first-child { + margin: 0 15px 0 20px; + } + &:nth-child(2) { + width: 60px; + height: 60px; + background-color: black; + border-radius: 100%; + margin-right: 12px; + } + } + p { + font-size: 24px; + font-weight: 700; + } + &:hover { + scale: 1.025; + } +} + +.leftSide { + @include displayFlex($j: start, $g: 20px); + width: 20vw; + .homeIcon { + width: 242px; + height: 70px; + margin-left: 20px; + } +} + +.middleSide { + width: 40vw; +} + +.rightSide { + width: 20vw; + @include displayFlex($j: end, $g: 20px); + p { + font-size: 28px; + font-weight: 700; + } + .img { + margin-right: 20px; + cursor: pointer; + .profileImg { + width: 80px; + height: 80px; + object-fit: cover; + border-radius: 50%; + } + .onlineIcon { + margin-left: -20px; + } + } + .positionPlanet { + margin-left: -24px; + margin-right: 12px; + margin-top: -54px; + } +} + +.suggestionBox::-webkit-scrollbar { + display: none; +} + +.menu { + position: absolute; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + z-index: 5; +} + +.whiteBox { + background-color: white; + @include displayFlex($g: 20px); + flex-direction: column; + width: 220px; + height: 160px; + border-top-left-radius: 40px; + border-bottom-left-radius: 40px; + border-bottom-right-radius: 40px; + position: absolute; + top: 110px; + right: 20px; + p { + font-size: 22px; + font-weight: 600; + cursor: pointer; + text-align: center; + padding: 8px; + &:hover { + width: 62%; + background-color: #edeefe; + border-radius: 15px; + color: #444df2; + } + } +} + +.arrowLeft { + display: none; +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD) { + .middleSide { + display: none; + } + + .rightSide, + .leftSide { + width: 50vw; + margin-left: 0; + } + + .profileImg { + margin: 0; + } +} + +@media screen and (max-width: 800px) { + .rightSide { + @include displayFlex($j: end, $g: 20px); + p { + display: none; + } + .img { + margin-right: 20px; + } + } + + .whiteBox { + @include displayFlex(); + width: 178px; + height: 122px; + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .whiteBox { + top: unset; + bottom: 0; + right: 0; + width: 100%; + height: 186px; + gap: 16px; + border-radius: 40px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + } + + .rightSide { + .img { + .profileImg { + width: 50px; + height: 50px; + } + .onlineIcon { + margin-left: -12px; + } + } + .positionPlanet { + margin-left: -38px; + margin-right: 6px; + margin-top: -34px; + } + } + + .leftSide { + @include displayFlex($j: start, $g: 8px); + .homeIcon { + width: 162px; + height: 45px; + } + } + + .logo { + img { + &:first-child { + margin: 0 12px 0 16px; + } + &:nth-child(2) { + width: 50px; + height: 50px; + background-color: black; + border-radius: 100%; + margin-right: 12px; + } + } + p { + font-size: 20px; + font-weight: 700; + } + &:hover { + scale: 1.025; + } + } +} diff --git a/src/app/shared/components/header/header.component.spec.ts b/src/app/shared/components/header/header.component.spec.ts new file mode 100644 index 0000000..4ff21e8 --- /dev/null +++ b/src/app/shared/components/header/header.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeaderComponent } from './header.component'; + +describe('HeaderComponent', () => { + let component: HeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HeaderComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(HeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/header/header.component.ts b/src/app/shared/components/header/header.component.ts new file mode 100644 index 0000000..81875c6 --- /dev/null +++ b/src/app/shared/components/header/header.component.ts @@ -0,0 +1,90 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { EditUserComponent } from './edit-user/edit-user.component'; +import { UserService } from '../../../service/user.service'; +import { SearchBarComponent } from './search-bar/search-bar.component'; +import { ToggleBooleanService } from '../../../service/toggle-boolean.service'; +import { ChatService } from '../../../service/chat.service'; +import { SharedService } from '../../../service/shared.service'; +import { SmallBtnComponent } from '../small-btn/small-btn.component'; +import { LanguageService } from '../../../service/language.service'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-header', + standalone: true, + imports: [ + CommonModule, + EditUserComponent, + SearchBarComponent, + SmallBtnComponent, + TranslateModule, + ], + templateUrl: './header.component.html', + styleUrl: './header.component.scss', +}) +export class HeaderComponent { + @Input() viewWidth: number = 0; + + openMenu: boolean = false; + showCurrentProfile: boolean = false; + closeProfil: boolean = false; + + constructor( + public userService: UserService, + public toggleBoolean: ToggleBooleanService, + public chatService: ChatService, + private sharedService: SharedService, + public languageService: LanguageService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + RESPONSIVE_THRESHOLD_MOBILE = this.sharedService.RESPONSIVE_THRESHOLD_MOBILE; + + /** + * Toggles the display of the side menu. + */ + showSideMenu() { + this.openMenu = !this.openMenu; + } + + /** + * Displays the current user's profile. + */ + showProfile() { + this.showCurrentProfile = true; + this.closeProfil = false; + } + + /** + * Logs out the current user. + */ + logout(): void { + this.userService.currentUserLogout(); + this.chatService.isSecondaryChatId = ''; + this.chatService.isSecondaryChatOpen = false; + } + + /** + * Updates the value indicating whether the current profile is displayed. + * @param value The new value indicating whether the current profile is displayed. + */ + updateTestValue(value: boolean) { + this.showCurrentProfile = value; + } + + /** + * Toggle the Sidebar. + */ + toggleSidebar() { + this.closeSecondaryChat(); + this.toggleBoolean.isSidebarOpen = !this.toggleBoolean.isSidebarOpen; + } + + /** + * Closes the secondary chat window. + */ + closeSecondaryChat() { + this.chatService.toggleSecondaryChat('none'); + } +} diff --git a/src/app/shared/components/header/search-bar/search-bar.component.html b/src/app/shared/components/header/search-bar/search-bar.component.html new file mode 100644 index 0000000..e810ad3 --- /dev/null +++ b/src/app/shared/components/header/search-bar/search-bar.component.html @@ -0,0 +1,86 @@ +
+ + +
+ + @if (filteredUsers.length > 0 && inputValue != '') { +
+

{{ 'search-bar-header.user' | translate }}:

+
+ @for (user of filteredUsers; track user) { +
+
+ + @if (user.status === true) { + + } @else { + + } +
+

+
+ } +
+
+ } @if (filteredChannels.length > 0 && inputValue != '') { +
+

{{ 'search-bar-header.channels' | translate }}:

+
+ @for (channel of filteredChannels; track channel) { +

+ # +

+ } +
+
+ } @if (filteredChats.length > 0 && inputValue != '') { +
+

{{ 'search-bar-header.thread' | translate }}:

+
+ @for (chat of filteredChats; track chat) { +
+

[ {{ getChannel(chat.channelId) }} ]

+
+

+
+
+ } +
+
+ } @if ((filteredUsers.length === 0 && inputValue != '') && + (filteredChannels.length === 0 && inputValue != '') && (filteredChats.length + === 0 && inputValue != '')) { +

{{ "search-bar.errorMessage" | translate }}

+ } +
+
diff --git a/src/app/shared/components/header/search-bar/search-bar.component.scss b/src/app/shared/components/header/search-bar/search-bar.component.scss new file mode 100644 index 0000000..5aeabd3 --- /dev/null +++ b/src/app/shared/components/header/search-bar/search-bar.component.scss @@ -0,0 +1,193 @@ +@import "./../../../../../styles.scss"; + +.inputPosition { + @include displayFlex(); + position: relative; + input { + width: 40vw; + height: 70px; + border-radius: 30px; + padding: 0 24px; + font-size: larger; + border: none; + outline: none; + } + .searchImg { + position: absolute; + right: 36px; + } +} + +.suggestionBox { + z-index: 5; + position: absolute; + top: 100%; + left: 0; + border-radius: 30px; + background-color: white; + box-shadow: rgb(79 98 117) 0px 20px 30px -10px; + scrollbar-width: none; + overflow: scroll; + -ms-overflow-style: none; + display: flex; + gap: 20px; + flex-direction: column; +} +.contantBox { + @include displayFlex($j: space-between, $a: flex-start); + width: 100%; + h4 { + width: 30%; + } + .ansersBox { + @include displayFlex($a: flex-start, $g: 4px); + flex-direction: column; + width: 70%; + } +} + +.contantBoxChats { + @include displayFlex($j: space-between, $a: flex-start); + flex-direction: column; + width: 100%; + .channelAnswers { + width: 100%; + @include displayFlex($g: 4px); + flex-direction: column; + .ansersBoxChats { + width: 100%; + @include displayFlex($j: space-between, $a: flex-start); + .threadNmae { + width: 30%; + } + .threadContetntBox { + width: 70%; + .threadContetnt { + width: fit-content; + padding: 4px; + &:hover { + background-color: #edeefe; + border-radius: 25px; + cursor: pointer; + } + } + } + } + } +} + +.channelName { + padding: 4px; + &:hover { + background-color: #edeefe; + border-radius: 25px; + cursor: pointer; + } +} + +.userDiv { + @include displayFlex(); + padding: 4px; + position: relative; + &:hover { + background-color: #edeefe; + border-radius: 25px; + cursor: pointer; + } + .userImgDiv { + @include displayFlex($j: space-between, $a: flex-end); + .userProfilImg { + width: 32px; + height: 32px; + object-fit: cover; + border-radius: 50%; + } + .userOnlineImg { + position: absolute; + left: 28px; + width: 12px; + height: 12px; + object-fit: cover; + } + } + p { + margin-left: 12px; + } +} + +.showSearchWindow { + animation: shwoSW 0.3s ease-in-out; + width: calc(40vw - 42px); + max-height: 40vh; + padding: 20px; +} + +@keyframes shwoSW { + from { + max-height: 0; + } + to { + max-height: 40vh; + padding: 20px; + } +} + +.hideSearchWindow { + animation: hideSW 0.3s ease-in-out; + width: calc(40vw - 42px); + max-height: 0; + padding: 0; +} + +@keyframes hideSW { + from { + max-height: 40vh; + padding: 20px; + } + to { + max-height: 0; + padding: 20px; + } +} + +/*------------- RESPONSIVE -------------*/ + +@media screen and (max-width: $RESPONSIVE_THRESHOLD) { + .inputPosition { + input { + width: calc(100vw - 72px); + height: 38px; + border-radius: 24px; + padding: 6px 12px; + border: 1px solid #adb0d9; + } + } + + .showSearchWindow, + .hideSearchWindow { + width: calc(100vw - 86px); + max-height: 60vh; + } +} + +@media screen and (max-width: $RESPONSIVE_THRESHOLD_MOBILE) { + .inputPosition { + input { + width: calc(100vw - 56px); + } + } + + .showSearchWindow, + .hideSearchWindow { + width: calc(100vw - 56px); + padding: 20px 10px; + } + + .hideSearchWindow { + padding: 0; + } + + .suggestionBox { + left: unset; + } +} diff --git a/src/app/shared/components/header/search-bar/search-bar.component.spec.ts b/src/app/shared/components/header/search-bar/search-bar.component.spec.ts new file mode 100644 index 0000000..d89e9f1 --- /dev/null +++ b/src/app/shared/components/header/search-bar/search-bar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SearchBarComponent } from './search-bar.component'; + +describe('SearchBarComponent', () => { + let component: SearchBarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SearchBarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SearchBarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/header/search-bar/search-bar.component.ts b/src/app/shared/components/header/search-bar/search-bar.component.ts new file mode 100644 index 0000000..42c2bc6 --- /dev/null +++ b/src/app/shared/components/header/search-bar/search-bar.component.ts @@ -0,0 +1,237 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { User } from '../../../../interface/user.interface'; +import { Channel } from '../../../../interface/channel.interface'; +import { Chat } from '../../../../interface/chat.interface'; +import { UserService } from '../../../../service/user.service'; +import { ToggleBooleanService } from '../../../../service/toggle-boolean.service'; +import { ChannleService } from '../../../../service/channle.service'; +import { ChatService } from '../../../../service/chat.service'; +import { DomSanitizer } from '@angular/platform-browser'; +import { Router, RouterLink } from '@angular/router'; +import { FormsModule } from '@angular/forms'; +import { HighlightPipe } from '../../../../highlight.pipe'; +import { TranslateModule } from '@ngx-translate/core'; +import { SharedService } from '../../../../service/shared.service'; + +@Component({ + selector: 'app-search-bar', + standalone: true, + templateUrl: './search-bar.component.html', + styleUrl: './search-bar.component.scss', + imports: [ + CommonModule, + FormsModule, + RouterLink, + HighlightPipe, + TranslateModule, + ], +}) +export class SearchBarComponent { + @Input() viewWidth: number = 0; + + openMenu: boolean = false; + showCurrentProfile: boolean = false; + isOnline: boolean = true; + closeProfil: boolean = false; + openSearchWindow: boolean = false; + inputValue: string = ''; + filteredUsers: User[] = []; + filteredChannels: Channel[] = []; + filteredChats: Chat[] = []; + + constructor( + public userService: UserService, + public toggleBoolean: ToggleBooleanService, + private channelService: ChannleService, + private chatService: ChatService, + public sanitizer: DomSanitizer, + private route: Router, + private sharedService: SharedService + ) {} + + RESPONSIVE_THRESHOLD = this.sharedService.RESPONSIVE_THRESHOLD; + + /** + * Closes the secondary chat window & sidebar. + */ + closeSecondaryChatAndSidebar() { + this.chatService.toggleSecondaryChat('none'); + if (this.viewWidth <= this.RESPONSIVE_THRESHOLD) { + this.toggleBoolean.isSidebarOpen = false; + this.inputValue = ''; + } + } + + /** + * Filters all information based on the input value. + * @param inputValue The input value entered by the user. + */ + filterAllInfo(inputValue: string) { + if (inputValue !== '') { + this.toggleBoolean.openSearchWindowHead = true; + const getInputValue = inputValue.toLowerCase().trim(); + this.filterUsersChannelsChats(getInputValue); + } else { + this.toggleBoolean.openSearchWindowHead = false; + } + } + + /** + * Filters users, channels, and chats based on the input value. + * @param inputValue The input value entered by the user. + */ + filterUsersChannelsChats(inputValue: string) { + const filterUsers = this.getFilterUsers(inputValue); + const filterChannels = this.getFilterChannels(inputValue); + const filterChants = this.getFilterChats(inputValue); + + this.sortPrvAndPublicMessages(filterChants); + + this.filteredUsers = filterUsers; + this.filteredChannels = filterChannels; + } + + /** + * Filters users based on the input value. + * @param inputValue The input value entered by the user. + * @returns An array of filtered users. + */ + getFilterUsers(inputValue: string) { + return this.userService.getUsers().filter((user) => { + const fullName = `${user.firstName} ${user.lastName}`.toLowerCase(); + return fullName.includes(inputValue); + }); + } + + /** + * Filters channels based on the input value. + * @param inputValue The input value entered by the user. + * @returns An array of filtered channels. + */ + getFilterChannels(inputValue: string) { + const userHasAccessChannels = this.checkUserHasAccessToChannel(); + return userHasAccessChannels.filter((channel) => { + const channelName = `${channel.name}`.toLowerCase(); + return channelName.includes(inputValue); + }); + } + + /** + * Filters chats based on the input value. + * @param inputValue The input value entered by the user. + * @returns An array of filtered chats. + */ + getFilterChats(inputValue: string) { + const userChannels = this.checkUserHasAccessToChannel(); + + return this.chatService.allChats.filter((chat) => { + const chatMessage = `${chat.message}`.toLowerCase(); + return ( + chatMessage.includes(inputValue) && + userChannels.some((channel) => channel.id === chat.channelId) + ); + }); + } + + /** + * Checks whether the user has access to a channel. + * @returns {Array} - A list of channels to which the user has access. + */ + checkUserHasAccessToChannel() { + const isUserAChannelMember = this.channelService.allChannels.some( + (channel) => + channel.addedUser.includes(this.userService.getCurrentUserId()) + ); + + if (isUserAChannelMember) { + return this.channelService.allChannels.filter((channel) => + channel.addedUser.includes(this.userService.getCurrentUserId()) + ); + } + return []; + } + + /** + * Retrieves the channel associated with the specified chat ID. + * @param chatID The ID of the chat. + * @returns The name of the channel. + */ + getChannel(chatID: string) { + if (this.inputValue != '') { + const filteredChatBoolean = this.filteredChats.some( + (chat) => chat.channelId === chatID + ); + if (filteredChatBoolean) { + const filteredChat = this.filteredChats.find( + (chat) => chat.channelId === chatID + ); + const channelName = this.channelService.allChannels.find( + (channel) => channel.id === filteredChat!.channelId + ); + return channelName!.name; + } + } else { + return ''; + } + return ''; + } + + /** + * Sorts private and public messages. + * @param chats The array of chats to sort. + */ + sortPrvAndPublicMessages(chats: Chat[]) { + const publicChats: Chat[] = []; + + for (const chat of chats) { + const isPublicChannel = this.channelService.allPrvChannels.some( + (prvChannel) => prvChannel.id === chat.channelId + ); + if (!isPublicChannel) { + publicChats.push(chat); + } + } + this.filteredChats = publicChats; + } + + /** + * Checks the route based on the specified user. + * @param user The user to check the route for. + */ + async checkRoute(user: User[]) { + const userId = user[0].id!; + const channelExistsBoolean = this.channelService.allPrvChannels.some( + (channel) => + (channel.creatorId === userId && + channel.talkToUserId === this.userService.getCurrentUserId()) || + (channel.creatorId === this.userService.getCurrentUserId() && + channel.talkToUserId === userId) + ); + if (!channelExistsBoolean) { + const id = await this.userService.createPrvChannel(userId); + if (id) { + this.route.navigateByUrl(`main/${id}`); + } + } + this.getRouteToPrvChat(userId, channelExistsBoolean); + } + + /** + * Navigates to the private chat route based on the specified user. + * @param userId The ID of the user. + * @param channelExistsBoolean A boolean indicating whether the channel exists. + */ + getRouteToPrvChat(userId: string, channelExistsBoolean: boolean) { + if (channelExistsBoolean) { + const existingChannel = this.channelService.allPrvChannels.find( + (channel) => + (channel.creatorId === userId && + channel.talkToUserId === this.userService.getCurrentUserId()) || + (channel.creatorId === this.userService.getCurrentUserId() && + channel.talkToUserId === userId) + ); + this.route.navigateByUrl(`main/${existingChannel!.id}`); + } + } +} diff --git a/src/app/shared/components/imprint/imprint.component.html b/src/app/shared/components/imprint/imprint.component.html new file mode 100644 index 0000000..444ceed --- /dev/null +++ b/src/app/shared/components/imprint/imprint.component.html @@ -0,0 +1,74 @@ +
+ +
+
+

{{ "imprint.headline" | translate }}

+ + +
+ {{ "imprint.tmg" | translate }} +

+
+
+

Andre Kempf

+

Großschneidersweg 2a

+

76149 Karlsruhe

+
+
+

Björn ten Eicken

+

Baisieperstraße 31

+

42859 Remscheid

+
+
+

Aleksander Demyanovych

+

Heidweilerstr. 23

+

54313 Zemmer

+
+
+

{{ "imprint.contact" | translate }}

+

+ {{ "imprint.tel" | translate }}: + 0172-4180328 +

+

+ {{ "imprint.mail" | translate }}: + mail@andre-kempf.com +

+
+

{{ "imprint.disclaimer" | translate }}:

+ +

{{ "imprint.liabilityContentHeadline" | translate }}

+ +

{{ "imprint.liabilityContentDescription" | translate }}

+ +

{{ "imprint.liabilityLinksHeadline" | translate }}

+ +

{{ "imprint.liabilityLinksDescription" | translate }}

+ +

{{ "imprint.copyrightHeadline" | translate }}

+ +

{{ "imprint.copyrightDescription" | translate }}

+ +

{{ "imprint.dataProtectionHeadline" | translate }}

+ +

{{ "imprint.dataProtectionDescription" | translate }}

+
+

+ {{ "imprint.sourceText0" | translate }} + {{ + "imprint.sourceLink0" | translate + }} + {{ "imprint.sourceText1" | translate }} + {{ + "imprint.sourceLink1" | translate + }} +

+
+
+
diff --git a/src/app/shared/components/imprint/imprint.component.scss b/src/app/shared/components/imprint/imprint.component.scss new file mode 100644 index 0000000..0105d3d --- /dev/null +++ b/src/app/shared/components/imprint/imprint.component.scss @@ -0,0 +1,105 @@ +section { + word-wrap: break-word; + padding-left: 16px; + padding-right: 16px; + background-color: #eceefe; +} +.container { + background-color: #ffff; + border-radius: 24px; + padding: 80px; + margin-left: 75px; + margin-right: 75px; +} +.header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 32px; + img { + width: 32px; + height: 32px; + cursor: pointer; + margin-left: 48px; + &:hover { + width: 36px; + height: 36px; + background-color: var(--light-gray); + border-radius: 18px; + } + } +} + +h1 { + font-size: 61px; + font-weight: 700; + padding-bottom: 24px; + color: #444df2; +} + +h2 { + font-size: 32px; + font-weight: 700; + padding: 48px 0 24px 0; + color: #444df2; +} + +h3 { + font-size: 20px; + font-weight: 700; + padding: 24px 0; + color: #444df2; +} + +p { + font-size: 16px; + font-weight: 400; + padding-bottom: 10px; +} + +a { + color: var(--light-blue); + text-decoration: none; + &:hover { + text-decoration: underline; + } +} + +.team { + display: flex; + justify-content: start; + gap: 98px; +} +.placholder { + height: 24px; +} + +/*------------- RESPONSIVE -------------*/ +@media screen and (max-width: 1040px) { + section { + padding-right: 0; + } + .team { + flex-direction: column; + gap: 21px; + } +} + +@media screen and (max-width: 910px) { + section { + padding-right: 0; + } +} +@media screen and (max-width: 600px) { + .container { + padding: 24px; + margin-left: 0px; + margin-right: 16px; + } +} + +@media screen and (max-width: 400px) { + h2 { + font-size: 24px; + } +} diff --git a/src/app/shared/components/imprint/imprint.component.spec.ts b/src/app/shared/components/imprint/imprint.component.spec.ts new file mode 100644 index 0000000..f2b9c25 --- /dev/null +++ b/src/app/shared/components/imprint/imprint.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ImprintComponent } from './imprint.component'; + +describe('Imprint', () => { + let component: ImprintComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ImprintComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ImprintComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/imprint/imprint.component.ts b/src/app/shared/components/imprint/imprint.component.ts new file mode 100644 index 0000000..0ac7c4c --- /dev/null +++ b/src/app/shared/components/imprint/imprint.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; +import { Location } from '@angular/common'; +import { TranslateModule } from '@ngx-translate/core'; +import { HeaderComponent } from "../login/header/header.component"; +import { SmallBtnComponent } from "../small-btn/small-btn.component"; +import { RouterLink } from '@angular/router'; + +@Component({ + selector: 'app-imprint', + standalone: true, + templateUrl: './imprint.component.html', + styleUrl: './imprint.component.scss', + imports: [TranslateModule, HeaderComponent, SmallBtnComponent,RouterLink] +}) +export class ImprintComponent { + constructor(private location: Location) {} + + + /** + * Navigates back to the previous location. + */ + backClicked() { + this.location.back(); + } +} diff --git a/src/app/shared/components/login/footer/footer.component.html b/src/app/shared/components/login/footer/footer.component.html new file mode 100644 index 0000000..b3f50d4 --- /dev/null +++ b/src/app/shared/components/login/footer/footer.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/shared/components/login/footer/footer.component.scss b/src/app/shared/components/login/footer/footer.component.scss new file mode 100644 index 0000000..0133ec4 --- /dev/null +++ b/src/app/shared/components/login/footer/footer.component.scss @@ -0,0 +1,33 @@ +.footer { + display: flex; + justify-content: center; + gap: 32px; + background-color: #eceefe; + padding-top: 132px; + padding-bottom: 24px; + width: 100vw; + + > a { + font-size: 18px; + font-weight: 400px; + text-decoration: none; + color: #797ef3; + padding-right: 8px; + padding: 0px; + padding: 4px 12px 4px 12px; + border-radius: 100px; + border: 1px solid #eceefe; + &:hover { + border: 1px solid #444df2; + } + } +} +.fontColor { + cursor: pointer; + color: #444df2; +} +@media (max-width: 570px) { + .footer { + padding-top: 32px; + } +} diff --git a/src/app/shared/components/login/footer/footer.component.spec.ts b/src/app/shared/components/login/footer/footer.component.spec.ts new file mode 100644 index 0000000..4647de8 --- /dev/null +++ b/src/app/shared/components/login/footer/footer.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FooterComponent } from './footer.component'; + +describe('FooterComponent', () => { + let component: FooterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FooterComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(FooterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/login/footer/footer.component.ts b/src/app/shared/components/login/footer/footer.component.ts new file mode 100644 index 0000000..5db97b2 --- /dev/null +++ b/src/app/shared/components/login/footer/footer.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-footer', + standalone: true, + imports: [RouterModule, TranslateModule], + templateUrl: './footer.component.html', + styleUrl: './footer.component.scss' +}) +export class FooterComponent { + +} diff --git a/src/app/shared/components/login/header/header.component.html b/src/app/shared/components/login/header/header.component.html new file mode 100644 index 0000000..995dd95 --- /dev/null +++ b/src/app/shared/components/login/header/header.component.html @@ -0,0 +1,5 @@ +
+
+ +
+
diff --git a/src/app/shared/components/login/header/header.component.scss b/src/app/shared/components/login/header/header.component.scss new file mode 100644 index 0000000..4cab410 --- /dev/null +++ b/src/app/shared/components/login/header/header.component.scss @@ -0,0 +1,13 @@ +.headerContainer { + display: flex; +} +.header { + margin: 75px; + display: flex; + background-color: #eceefe; +} +@media screen and (max-width: 600px) { + .headerContainer { + justify-content: center; + } +} diff --git a/src/app/shared/components/login/header/header.component.spec.ts b/src/app/shared/components/login/header/header.component.spec.ts new file mode 100644 index 0000000..4ff21e8 --- /dev/null +++ b/src/app/shared/components/login/header/header.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeaderComponent } from './header.component'; + +describe('HeaderComponent', () => { + let component: HeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HeaderComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(HeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/login/header/header.component.ts b/src/app/shared/components/login/header/header.component.ts new file mode 100644 index 0000000..4f46d3b --- /dev/null +++ b/src/app/shared/components/login/header/header.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-header', + standalone: true, + imports: [], + templateUrl: './header.component.html', + styleUrl: './header.component.scss', +}) +export class HeaderComponent {} diff --git a/src/app/shared/components/login/mixins/mixin.scss b/src/app/shared/components/login/mixins/mixin.scss new file mode 100644 index 0000000..a98ec59 --- /dev/null +++ b/src/app/shared/components/login/mixins/mixin.scss @@ -0,0 +1,137 @@ +@mixin SektionBody { + display: flex; + justify-content: space-between; + align-items: center; + flex-direction: column; + background: #eceefe; + height: 100vh; +} +@mixin Card { + max-width: 606px; + width: 100%; + background-color: #fff; + border-radius: 30px; + box-sizing: border-box; + padding: 32px; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + gap: 16px; + height: 690px; +} +@mixin topText { + margin-bottom: 8px; + display: flex; + justify-content: center; + align-items: center; + width: 110%; + > span { + text-align: center; + font-size: 46px; + font-weight: 700; + color: #444df2; + } +} + +.loginBackImg { + cursor: pointer; +} +@mixin InfoText { + margin-bottom: 24px; + text-align: center; + max-width: 486px; + > span { + font-size: 20px; + font-weight: 400; + line-height: 24px; + } +} + +@mixin inputStyle { + padding-left: 60px; + border: 1px solid #ffff; + font-size: 18px; + font-weight: 500; + outline: none; + width: 100%; + box-sizing: border-box; + background: #eceefe; + height: 60px; + border-radius: 100px; + &:hover { + border: 1px solid#686868; + } + &:focus { + border: 1px solid #444df2; + } +} +@mixin errorStyle { + color: #ed1e79; + position: absolute; + margin: 4px; + font-size: 14px; +} + +@mixin buttonGrey { + padding: 12px 25px; + color: #fff; + background-color: #cacad6; + outline: none; + border: none; + box-sizing: border-box; + transition: 0.2s; + border-radius: 25px; + font-size: 18px; + font-weight: 600; +} +@mixin aktivButtonBlue { + padding: 12px 25px; + color: #fff; + background-color: #444df2; + outline: none; + border: none; + box-sizing: border-box; + transition: 0.2s; + border-radius: 25px; + font-size: 18px; + font-weight: 600; + cursor: pointer; + &:hover { + background-color: #676eec; + } +} + +.mobileRegisterContainer { + display: none; + > div { + display: flex; + flex-direction: column; + gap: 20px; + text-align: center; + > span { + font-weight: 400; + font-size: 18px; + } + } +} +.mobileCreateAccountContainer { + display: flex; + justify-content: end; +} +.mobileCreateAccoun { + font-family: Figtree, sans-serif, Nunito; + color: #797ef3; + cursor: pointer; + padding: 4px 12px 4px 12px; + border-radius: 100px; + border: 1px solid #eceefe; + font-weight: 400; + font-size: 18px; + &:hover { + font-weight: 500; + background-color: #eceefe; + color: #444df2; + border: 1px solid #444df2; + } +} diff --git a/src/app/shared/components/login/start-header/start-header.component.html b/src/app/shared/components/login/start-header/start-header.component.html new file mode 100644 index 0000000..c962e31 --- /dev/null +++ b/src/app/shared/components/login/start-header/start-header.component.html @@ -0,0 +1,55 @@ +
+
+
+
+ +
+ DABubble +
+
+
+ +
+
+ {{ "start-header.new" | translate }} +
+ {{ + "start-header.create" | translate + }} +
+
+
+ +
diff --git a/src/app/shared/components/login/start-header/start-header.component.scss b/src/app/shared/components/login/start-header/start-header.component.scss new file mode 100644 index 0000000..9740725 --- /dev/null +++ b/src/app/shared/components/login/start-header/start-header.component.scss @@ -0,0 +1,308 @@ +@import "../../../../../styles.scss"; + +.headerContainer { + display: flex; + width: 97vw; + justify-content: space-between; + height: 228px; +} + +.header { + display: flex; + background-color: #eceefe; +} + +.registerContainer { + position: absolute; + top: 90px; + right: 71px; + + > div { + display: flex; + flex-direction: column; + gap: 20px; + > span { + font-weight: 400; + font-size: 18px; + } + } +} + +.createAccountContainer { + display: flex; + justify-content: end; +} + +.createAccoun { + text-align: end; + font-family: Figtree, sans-serif, Nunito; + color: #797ef3; + cursor: pointer; + padding-right: 8px; + padding: 0px; + padding: 4px 12px 4px 12px; + border-radius: 100px; + border: 1px solid #eceefe; + font-weight: 400; + font-size: 18px; + margin-right: -13px; + &:hover { + font-weight: 500; + background-color: #eceefe; + color: #444df2; + border: 1px solid #444df2; + } +} + +.switchLanguage { + position: absolute; + right: 26px; + top: 18px; +} +// animation start ------------------------------------------------------------> + +.background { + z-index: 2; + position: absolute; + top: 0; + left: 0; + background: linear-gradient(1.46deg, #313ae6 1.22%, #797ef3 98.76%); + width: 100%; + height: 100%; + transition: 1s; + overflow-x: hidden !important; + overflow-y: hidden !important; +} + +.background.d-none { + display: none; +} + +.opacity { + opacity: 0; +} + +.logo { + position: absolute; + top: 50%; + left: 60%; + transform: translate(-50%, -50%); + display: flex; + align-items: center; + animation: logoAnimation-slide 0.5s ease-in forwards 1s; + background-size: contain; + gap: 11px; + z-index: 999; +} + +@keyframes logoAnimation-slide { + 0% { + top: 50%; + left: 60%; + transform: translate(-50%, -50%); + } + 100% { + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } +} + +//animation to end Position ------------------------------------------------------------> + +.logoEndPosition { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + animation: animationToEndPosiotion 0.5s ease-in forwards 1s; + background-size: contain; + z-index: 999; +} + +.imgEndPosiotion { + animation: imgSize 0.5s ease-in forwards 1s; +} + +@keyframes imgSize { + 0% { + width: 187px; + height: 184px; + } + 90% { + width: 167px; + height: 154px; + } + 100% { + width: 70px; + height: 70px; + } +} + +@keyframes animationToEndPosiotion { + 0% { + top: 50%; + left: 50%; + width: 240px; + transform: translate(-50%, -50%); + } + 100% { + top: 125px; + left: 195px; + width: 240px; + gap: 11px; + height: 70px; + } +} + +.logo-text { + top: 50%; + left: 50%; + overflow: hidden; + white-space: nowrap; + transition: clip-path 0.5s ease-in-out; + animation: textAnimation 0.5s ease-in forwards 1.1s; + z-index: 900; + clip-path: inset(0 100% 0 0); +} + +@keyframes textAnimation { + 0% { + clip-path: inset(0 100% 0 0); + } + 100% { + clip-path: inset(0 0 0 0); + } +} + +@keyframes spanFontSizeChange { + 0% { + font-size: 64px; + } + 50% { + font-size: 50px; + } + 100% { + font-size: 32px; + color: black; + } +} + +.logo-text-span { + animation: spanFontSizeChange 0.7s ease-in forwards 3.25s; + font-size: 64px; + font-weight: 800; + color: white; +} + +// Final Class Contains ------------------------------------------------------------> + +.final-span-position { + font-size: 32px; + color: black; + font-weight: 800; + animation: none; +} + +.final-img-position { + width: 70px; + height: 70px; +} + +.final-div-position { + position: absolute; + top: 125px; + transform: translate(-50%, -50%); + display: flex; + align-items: center; + background-size: contain; + z-index: 999; + gap: 11px; + left: 193.5px; +} + +@media (max-width: 570px) { + .headerContainer { + height: 95px; + } + .final-div-position { + left: 50%; + top: 50px; + } + .registerContainer { + display: none; + > div { + align-items: center; + } + } + .createAccoun { + margin-right: 0; + } + .logoEndPosition { + animation: none; + animation: animationToEndPosiotionMobile 0.5s ease-in forwards 1s; + } + + @keyframes animationToEndPosiotionMobile { + 0% { + top: 50%; + left: 50%; + width: 70px; + } + 100% { + top: 50px; + left: 50%; + width: 237.55px; + gap: 11px; + } + } + .mobileImg { + height: 90px; + } + .logo-text-span { + font-size: 34px; + font-weight: 800; + color: white; + animation: none; + animation: spanFontSizeChangeMobile 0.7s ease-in forwards 3.25s; + } + @keyframes spanFontSizeChangeMobile { + 0% { + font-size: 34px; + } + 50% { + font-size: 32px; + } + 100% { + font-size: 32px; + color: black; + } + } + + .imgEndPosiotion { + animation: none; + animation: imgSizeMobile 0.5s ease-in forwards 1s; + } + + @keyframes imgSizeMobile { + 0% { + width: 90px; + height: 90px; + } + 90% { + width: 70px; + height: 70px; + } + 100% { + width: 70px; + height: 70px; + } + } +} + +@media screen and (max-width: 570px) { + .switchLanguage { + right: 10px; + top: 8px; + } +} diff --git a/src/app/shared/components/login/start-header/start-header.component.spec.ts b/src/app/shared/components/login/start-header/start-header.component.spec.ts new file mode 100644 index 0000000..e2eab10 --- /dev/null +++ b/src/app/shared/components/login/start-header/start-header.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StartHeaderComponent } from './start-header.component'; + +describe('StartHeaderComponent', () => { + let component: StartHeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [StartHeaderComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(StartHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/login/start-header/start-header.component.ts b/src/app/shared/components/login/start-header/start-header.component.ts new file mode 100644 index 0000000..d234175 --- /dev/null +++ b/src/app/shared/components/login/start-header/start-header.component.ts @@ -0,0 +1,88 @@ +import { Component, HostListener, Input } from '@angular/core'; +import { CommonModule, NgStyle } from '@angular/common'; +import { RouterLink } from '@angular/router'; +import { loginService } from '../../../../service/login.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { LanguageService } from '../../../../service/language.service'; +import { SmallBtnComponent } from '../../small-btn/small-btn.component'; +import { SharedService } from '../../../../service/shared.service'; + +@Component({ + selector: 'app-start-header', + standalone: true, + imports: [ + CommonModule, + RouterLink, + NgStyle, + TranslateModule, + SmallBtnComponent, + ], + templateUrl: './start-header.component.html', + styleUrl: './start-header.component.scss', +}) +export class StartHeaderComponent { + @Input() introCompleteStatus: boolean = false; + @Input() display: string = ''; + animationStart: boolean = false; + animationLogo: boolean = false; + d_none: boolean = false; + animationBackground: boolean = false; + animationToEndPosiotion: boolean = false; + animationsBlock: boolean = false; + viewWidth: number = 0; + + constructor( + public loginService: loginService, + public LanguageService: LanguageService + ) {} + + /** + * Initializes the component and decides whether to start animations based on the login service state. + */ + ngOnInit(): void { + if (!this.loginService.getAnimationState()) { + this.triggerAnimations(); + } else { + this.d_none = true; + } + } + + /** + * Triggers a sequence of animations with nested timeouts to manage their execution order and timing. + */ + triggerAnimations(): void { + setTimeout(() => { + this.animationStart = true; + setTimeout(() => { + this.animationLogo = true; + setTimeout(() => { + setTimeout(() => { + this.animationBackground = true; + }, 1000); + this.animationToEndPosiotion = true; + this.loginService.setAnimationState(true); + setTimeout(() => { + this.d_none = true; + this.loginService.setFinalClass(true); + this.animationsBlock = true; + }, 2000); + }, 2000); + }, 300); + }, 1000); + } + + /** + * Listens for window resize events. + */ + @HostListener('window:resize') + onResize() { + this.updateViewWidth(); + } + + /** + * Updates the view width based on the current window width. + */ + private updateViewWidth() { + this.viewWidth = window.innerWidth; + } +} diff --git a/src/app/shared/components/overlay/overlay.component.html b/src/app/shared/components/overlay/overlay.component.html new file mode 100644 index 0000000..3e204e9 --- /dev/null +++ b/src/app/shared/components/overlay/overlay.component.html @@ -0,0 +1,17 @@ +
+
+ @if (['png', 'jpg', 'jpeg', 'gif'].includes(getFileType(overlayData))) { + Overlay Image + } @if (['mp4'].includes(getFileType(overlayData))) { + + } + + +
+
diff --git a/src/app/shared/components/overlay/overlay.component.scss b/src/app/shared/components/overlay/overlay.component.scss new file mode 100644 index 0000000..a5d07a1 --- /dev/null +++ b/src/app/shared/components/overlay/overlay.component.scss @@ -0,0 +1,37 @@ +/* overlay.component.css */ +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + backdrop-filter: blur(5px); + display: flex; + justify-content: center; + align-items: center; + z-index: 999; +} + +.overlayContent { + display: flex; + align-items: center; + justify-content: center; + width: 75%; + height: auto; + img { + width: 100%; + height: auto; + border-radius: 12px; + } + video { + width: 100%; + height: auto; + } +} + +app-small-btn { + position: absolute; + top: 24px; + right: 24px; + z-index: 5; +} diff --git a/src/app/shared/components/overlay/overlay.component.spec.ts b/src/app/shared/components/overlay/overlay.component.spec.ts new file mode 100644 index 0000000..796c7ff --- /dev/null +++ b/src/app/shared/components/overlay/overlay.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OverlayComponent } from './overlay.component'; + +describe('OverlayComponent', () => { + let component: OverlayComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [OverlayComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OverlayComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/overlay/overlay.component.ts b/src/app/shared/components/overlay/overlay.component.ts new file mode 100644 index 0000000..3fe19d9 --- /dev/null +++ b/src/app/shared/components/overlay/overlay.component.ts @@ -0,0 +1,67 @@ +import { + Component, + HostListener, + OnInit +} from '@angular/core'; +import { OverlayService } from '../../../service/overlay.service'; +import { CommonModule } from '@angular/common'; +import { SmallBtnComponent } from '../small-btn/small-btn.component'; + +@Component({ + selector: 'app-overlay', + standalone: true, + imports: [CommonModule, SmallBtnComponent], + templateUrl: './overlay.component.html', + styleUrl: './overlay.component.scss', +}) +export class OverlayComponent implements OnInit { + overlayData: any; + + constructor(private overlayService: OverlayService) {} + + + /** + * Initializes the component and subscribes to overlay data changes. + */ + ngOnInit(): void { + this.overlayService.overlayData$.subscribe((data) => { + this.overlayData = data; + }); + } + + + /** + * Extracts the file type from the file name. + * @param file The file name. + * @returns The file type. + */ + getFileType(file: string): string { + const extension = file.split('.').pop()?.toLowerCase(); + const getTag = extension!.split('?')[0]; + return getTag || ''; + } + + + /** + * Closes the overlay. + */ + onCloseOverlay() { + this.overlayData = ''; + } + + + /** + * Checks if the contact edit overlay is open and closes it if the click is outside the overlay content. + * @param event The mouse event. + */ + @HostListener('document:click', ['$event']) + checkOpenContactEdit(event: MouseEvent) { + const targetElement = event.target as HTMLElement; + if ( + !targetElement.closest('.overlayContent') && + !targetElement.closest('.attachments') + ) { + this.onCloseOverlay(); + } + } +} diff --git a/src/app/shared/components/privacy-policy/privacy-policy.component.html b/src/app/shared/components/privacy-policy/privacy-policy.component.html new file mode 100644 index 0000000..4d05c98 --- /dev/null +++ b/src/app/shared/components/privacy-policy/privacy-policy.component.html @@ -0,0 +1,229 @@ +
+ +
+
+

{{ "privacy-policy.headline" | translate }}

+ + +
+

+ {{ "privacy-policy.preambleHeadline" | translate }} +

+

+ {{ "privacy-policy.preambleDescription" | translate }} +

+ +

{{ "privacy-policy.ContentHeadline" | translate }}

+ +

{{ "privacy-policy.Content1" | translate }}

+ +
+
+

Andre Kempf

+

Großschneidersweg 2a

+

76149 Karlsruhe

+
+
+

Björn ten Eicken

+

Baisieperstraße 31

+

42859 Remscheid

+
+
+

Aleksander Demyanovych

+

Heidweilerstr. 23

+

54313 Zemmer

+
+
+
+

+ {{ "imprint.tel" | translate }}: + 0172-4180328 +

+

+ {{ "imprint.mail" | translate }}: + mail@andre-kempf.com +

+ +

{{ "privacy-policy.Content2" | translate }}

+

+ {{ "privacy-policy.Content2Description" | translate }} +

+

{{ "privacy-policy.Content2Section0" | translate }}

+
    +
  • {{ "privacy-policy.Content2Section0List" | translate }}
  • +
+

{{ "privacy-policy.Content2Section1" | translate }}

+
    +
  • {{ "privacy-policy.Content2Section1List" | translate }}
  • +
+

{{ "privacy-policy.Content2Section2" | translate }}

+
    +
  • {{ "privacy-policy.Content2Section2List" | translate }}
  • +
+

{{ "privacy-policy.Content3" | translate }}

+

+ {{ "privacy-policy.Content3Header0" | translate }}
+ {{ "privacy-policy.Content3Description0" | translate }} +

+
    +
  • + {{ "privacy-policy.Content3Header1" | translate }}
    + {{ "privacy-policy.Content3Description1" | translate }} +
  • +
+

+ {{ "privacy-policy.Content3Header2" | translate }}
+ {{ "privacy-policy.Content3Description2" | translate }} +

+ +

{{ "privacy-policy.Content4" | translate }}

+

+ {{ "privacy-policy.Content4Description0" | translate }} +

+

+ {{ "privacy-policy.Content4Description1" | translate }} +

+

+ {{ "privacy-policy.Content4Description2" | translate }} +

+ +

{{ "privacy-policy.Content5" | translate }}

+

+ {{ "privacy-policy.Content5Description" | translate }} +

+ +

{{ "privacy-policy.Content6" | translate }}

+

+ {{ "privacy-policy.Content6Description0" | translate }} +

+ {{ "privacy-policy.Content6Description1" | translate }} +
    +
  • + {{ "privacy-policy.Content6Section0" | translate }}
    + {{ "privacy-policy.Content6Section0List" | translate }} +
  • +
  • + {{ "privacy-policy.Content6Section1" | translate }} +
    + {{ "privacy-policy.Content6Section1List" | translate }} +
  • +
  • + {{ "privacy-policy.Content6Section2" | translate }}
    + {{ "privacy-policy.Content6Section2List" | translate }} +
  • +
  • + {{ "privacy-policy.Content6Section3" | translate }}
    + {{ "privacy-policy.Content6Section3List" | translate }} +
  • +
  • + {{ "privacy-policy.Content6Section4" | translate }}
    + {{ "privacy-policy.Content6Section4List" | translate }} +
  • +
  • + {{ "privacy-policy.Content6Section5" | translate }}
    + {{ "privacy-policy.Content6Section5List" | translate }} +
  • +
+ +

{{ "privacy-policy.Content7" | translate }}

+

+ {{ "privacy-policy.Content7Description0" | translate }} +

+

+ {{ "privacy-policy.Content7Description1" | translate }} +

+ +

{{ "privacy-policy.Content8" | translate }}

+

+ {{ "privacy-policy.Content8Description0" | translate }} +

+
    +
  • + {{ "privacy-policy.Content8Section0" | translate }}
    + {{ "privacy-policy.Content8Section0List" | translate }} +
  • +
  • + {{ "privacy-policy.Content8Section1" | translate }}
    + {{ "privacy-policy.Content8Section1List" | translate }} +
  • +
  • + {{ "privacy-policy.Content8Section2" | translate }}
    + {{ "privacy-policy.Content8Section2List" | translate }} +
  • +
+
+

+ {{ "privacy-policy.sourceText" | translate }} +

+
+
+
diff --git a/src/app/shared/components/privacy-policy/privacy-policy.component.scss b/src/app/shared/components/privacy-policy/privacy-policy.component.scss new file mode 100644 index 0000000..53a856b --- /dev/null +++ b/src/app/shared/components/privacy-policy/privacy-policy.component.scss @@ -0,0 +1,139 @@ +section { + word-wrap: break-word; + padding-left: 16px; + padding-right: 16px; + background-color: #eceefe; +} +.container { + background-color: #ffff; + border-radius: 24px; + padding: 80px; + margin-left: 75px; + margin-right: 75px; +} +.headerContainer { + display: flex; + width: 99vw !important; +} +.header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 32px; + img { + width: 32px; + height: 32px; + cursor: pointer; + margin-left: 48px; + &:hover { + width: 36px; + height: 36px; + background-color: var(--light-gray); + border-radius: 18px; + } + } +} + +h1 { + font-size: 61px; + font-weight: 700; + color: #444df2; + width: 100%; +} + +h2 { + font-size: 32px; + font-weight: 700; + padding: 24px 0 12px 0; + color: #444df2; +} + +h3 { + font-size: 20px; + font-weight: 700; + padding: 24px 0; + color: #444df2; +} + +p { + font-size: 16px; + font-weight: 400; + padding-bottom: 10px; +} + +ul { + padding: 12px; + li { + padding: 5px; + } +} + +a { + color: var(--light-blue); + text-decoration: none; + &:hover { + text-decoration: underline; + } +} +.team { + display: flex; + justify-content: start; + gap: 98px; +} +.placholder { + height: 24px; +} + +/*------------- RESPONSIVE -------------*/ +@media screen and (max-width: 1046px) { + h1 { + font-size: 44px; + } + .team { + gap: 48px; + } +} +@media screen and (max-width: 800px) { + .container { + padding: 24px; + margin-left: 0px; + margin-right: 16px; + } +} +@media screen and (max-width: 936px) { + .container { + padding: 24px; + margin-left: 0px; + margin-right: 16px; + } +} +@media screen and (max-width: 910px) { + section { + padding-right: 0; + } +} +@media screen and (max-width: 675px) { + .team { + gap: 12px; + flex-direction: column; + } +} +@media screen and (max-width: 600px) { + .header { + align-items: end; + > h1 { + font-size: 40px; + width: 88%; + } + } +} +@media screen and (max-width: 400px) { + .header { + > h1 { + font-size: 35px; + } + } + h2 { + font-size: 31px; + } +} diff --git a/src/app/shared/components/privacy-policy/privacy-policy.component.spec.ts b/src/app/shared/components/privacy-policy/privacy-policy.component.spec.ts new file mode 100644 index 0000000..51a0589 --- /dev/null +++ b/src/app/shared/components/privacy-policy/privacy-policy.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PrivacyPolicyComponent } from './privacy-policy.component'; + +describe('PrivacyPolicyComponent', () => { + let component: PrivacyPolicyComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PrivacyPolicyComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PrivacyPolicyComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/privacy-policy/privacy-policy.component.ts b/src/app/shared/components/privacy-policy/privacy-policy.component.ts new file mode 100644 index 0000000..90c3c53 --- /dev/null +++ b/src/app/shared/components/privacy-policy/privacy-policy.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; +import { Location } from '@angular/common'; +import { TranslateModule } from '@ngx-translate/core'; +import { HeaderComponent } from "../login/header/header.component"; +import { SmallBtnComponent } from "../small-btn/small-btn.component"; +import { RouterLink } from '@angular/router'; + +@Component({ + selector: 'app-privacy-policy', + standalone: true, + templateUrl: './privacy-policy.component.html', + styleUrl: './privacy-policy.component.scss', + imports: [TranslateModule, HeaderComponent, SmallBtnComponent, RouterLink] +}) +export class PrivacyPolicyComponent { + constructor(private location: Location) {} + + + /** + * Navigates back to the previous location in the browser history. + */ + backClicked() { + this.location.back(); + } +} diff --git a/src/app/shared/components/small-btn/small-btn.component.html b/src/app/shared/components/small-btn/small-btn.component.html new file mode 100644 index 0000000..9d59f6c --- /dev/null +++ b/src/app/shared/components/small-btn/small-btn.component.html @@ -0,0 +1,19 @@ +
+ +
diff --git a/src/app/shared/components/small-btn/small-btn.component.scss b/src/app/shared/components/small-btn/small-btn.component.scss new file mode 100644 index 0000000..0d3d6e9 --- /dev/null +++ b/src/app/shared/components/small-btn/small-btn.component.scss @@ -0,0 +1,17 @@ +.smallBtn { + display: flex; + justify-content: center; + align-items: center; + border-radius: 100%; + width: 0; + height: 0; + cursor: pointer; + transition: 0.125s ease-in-out; + &:hover { + background-color: var(--btnBgHoverColor); + img { + scale: 1.1; + filter: var(--filter); + } + } +} diff --git a/src/app/shared/components/small-btn/small-btn.component.spec.ts b/src/app/shared/components/small-btn/small-btn.component.spec.ts new file mode 100644 index 0000000..4409f6e --- /dev/null +++ b/src/app/shared/components/small-btn/small-btn.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SmallBtnComponent } from './small-btn.component'; + +describe('SmallBtnComponent', () => { + let component: SmallBtnComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SmallBtnComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SmallBtnComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/small-btn/small-btn.component.ts b/src/app/shared/components/small-btn/small-btn.component.ts new file mode 100644 index 0000000..51e14ba --- /dev/null +++ b/src/app/shared/components/small-btn/small-btn.component.ts @@ -0,0 +1,19 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'app-small-btn', + standalone: true, + imports: [CommonModule], + templateUrl: './small-btn.component.html', + styleUrl: './small-btn.component.scss', +}) +export class SmallBtnComponent { + @Input() imgSrc: string = ''; + @Input() imgSize: string = '14px'; + @Input() imgFilter: string = + 'brightness(0) saturate(100%) invert(33%) sepia(23%) saturate(5211%) hue-rotate(224deg) brightness(96%) contrast(97%)'; + @Input() btnSize: string = '28px'; + @Input() btnBgColor: string = ''; + @Input() btnBgHoverColor: string = '#edeefe'; +} diff --git a/src/app/shared/components/user/user.component.html b/src/app/shared/components/user/user.component.html new file mode 100644 index 0000000..cf90ddb --- /dev/null +++ b/src/app/shared/components/user/user.component.html @@ -0,0 +1,28 @@ +
+
+
+

Profile

+ +
+ + + +
+

Max Müller

+
+ +

Aktiv

+
+ +
+ +
+

{{ 'user.email' | translate }}

+ maxMüller@ffe.de +
+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/shared/components/user/user.component.scss b/src/app/shared/components/user/user.component.scss new file mode 100644 index 0000000..8b97e69 --- /dev/null +++ b/src/app/shared/components/user/user.component.scss @@ -0,0 +1,88 @@ +@import '../../../../styles.scss'; + +.mainBox{ + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.3); + @include displayFlex(); + z-index: 5; + .whiteBox{ + width: 400px; + height: auto; + background-color: whitesmoke; + border-radius: 15px; + @include displayFlex(); + flex-direction: column; + padding-top: 32px; + .boxHeader{ + width: 360px; + @include displayFlex($j: space-between); + >p{ + font-size: 20px; + font-weight: 600; + margin: 0; + } + >img{ + cursor: pointer; + } + + } + .profileImg{ + width: 200px; + object-fit: cover; + border-radius: 50%; + margin: 56px; + } + >button{ + @include displayFlex($g: 12px); + background-color: #444df2; + border: none; + border-radius: 25px; + padding: 12px; + padding-left: 22px; + padding-right: 22px; + font-size: larger; + font-weight: 500; + color: white; + margin: 32px; + cursor: pointer; + } + } +} + +.detailsBox{ + width: 360px; + h1{ + font-size: 32px; + font-weight: 700; + margin-bottom: 20px; + } + .statusBox{ + @include displayFlex($j:flex-start, $g: 12px); + margin-bottom: 40px; + >p{ + margin: 0; + font-size: medium; + font-weight: 500; + } + } + +} + +.fontColorGreen{ + color: #92C83E; +} + +.emailBox{ + @include displayFlex($j: flex-start, $a: flex-start, $g: 20px); + .emailH2{ + >a{ + color: #4EA1FF; + font-size: 16px; + text-decoration: none; + } + } +} \ No newline at end of file diff --git a/src/app/shared/components/user/user.component.spec.ts b/src/app/shared/components/user/user.component.spec.ts new file mode 100644 index 0000000..04025f1 --- /dev/null +++ b/src/app/shared/components/user/user.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserComponent } from './user.component'; + +describe('UserComponent', () => { + let component: UserComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UserComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/user/user.component.ts b/src/app/shared/components/user/user.component.ts new file mode 100644 index 0000000..edc8b2a --- /dev/null +++ b/src/app/shared/components/user/user.component.ts @@ -0,0 +1,22 @@ +import { CommonModule } from '@angular/common'; +import { Component } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; + +@Component({ + selector: 'app-user', + standalone: true, + imports: [CommonModule, TranslateModule], + templateUrl: './user.component.html', + styleUrl: './user.component.scss' +}) +export class UserComponent { + isOnline = true; + openProfil = false; + + /** + * Toggles the display of the side menu for user profile. + */ + showSideMenu() { + this.openProfil = !this.openProfil; + } +} diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assets/fonts/figtree-v5-latin-500.woff2 b/src/assets/fonts/figtree-v5-latin-500.woff2 new file mode 100644 index 0000000..43944b1 Binary files /dev/null and b/src/assets/fonts/figtree-v5-latin-500.woff2 differ diff --git a/src/assets/fonts/figtree-v5-latin-600.woff2 b/src/assets/fonts/figtree-v5-latin-600.woff2 new file mode 100644 index 0000000..5ad11a8 Binary files /dev/null and b/src/assets/fonts/figtree-v5-latin-600.woff2 differ diff --git a/src/assets/fonts/figtree-v5-latin-700.woff2 b/src/assets/fonts/figtree-v5-latin-700.woff2 new file mode 100644 index 0000000..6039759 Binary files /dev/null and b/src/assets/fonts/figtree-v5-latin-700.woff2 differ diff --git a/src/assets/fonts/figtree-v5-latin-regular.woff2 b/src/assets/fonts/figtree-v5-latin-regular.woff2 new file mode 100644 index 0000000..c359928 Binary files /dev/null and b/src/assets/fonts/figtree-v5-latin-regular.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-200.woff2 b/src/assets/fonts/nunito-sans-v15-latin-200.woff2 new file mode 100644 index 0000000..d6e06b6 Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-200.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-200italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-200italic.woff2 new file mode 100644 index 0000000..83020a4 Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-200italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-300.woff2 b/src/assets/fonts/nunito-sans-v15-latin-300.woff2 new file mode 100644 index 0000000..ab4c92b Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-300.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-300italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-300italic.woff2 new file mode 100644 index 0000000..8f97fef Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-300italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-500.woff2 b/src/assets/fonts/nunito-sans-v15-latin-500.woff2 new file mode 100644 index 0000000..8de7afb Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-500.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-500italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-500italic.woff2 new file mode 100644 index 0000000..1b1ac10 Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-500italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-600.woff2 b/src/assets/fonts/nunito-sans-v15-latin-600.woff2 new file mode 100644 index 0000000..9b159e6 Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-600.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-600italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-600italic.woff2 new file mode 100644 index 0000000..eebb0a2 Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-600italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-700.woff2 b/src/assets/fonts/nunito-sans-v15-latin-700.woff2 new file mode 100644 index 0000000..9a8b29b Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-700.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-700italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-700italic.woff2 new file mode 100644 index 0000000..6b0835c Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-700italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-800.woff2 b/src/assets/fonts/nunito-sans-v15-latin-800.woff2 new file mode 100644 index 0000000..2d6a755 Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-800.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-800italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-800italic.woff2 new file mode 100644 index 0000000..282aa0a Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-800italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-900.woff2 b/src/assets/fonts/nunito-sans-v15-latin-900.woff2 new file mode 100644 index 0000000..d50836b Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-900.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-900italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-900italic.woff2 new file mode 100644 index 0000000..257ca3f Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-900italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-italic.woff2 b/src/assets/fonts/nunito-sans-v15-latin-italic.woff2 new file mode 100644 index 0000000..ffafc8b Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-italic.woff2 differ diff --git a/src/assets/fonts/nunito-sans-v15-latin-regular.woff2 b/src/assets/fonts/nunito-sans-v15-latin-regular.woff2 new file mode 100644 index 0000000..52e3f8e Binary files /dev/null and b/src/assets/fonts/nunito-sans-v15-latin-regular.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-200.woff2 b/src/assets/fonts/nunito-v26-latin-200.woff2 new file mode 100644 index 0000000..5ef33cd Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-200.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-200italic.woff2 b/src/assets/fonts/nunito-v26-latin-200italic.woff2 new file mode 100644 index 0000000..d7815e2 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-200italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-300.woff2 b/src/assets/fonts/nunito-v26-latin-300.woff2 new file mode 100644 index 0000000..ca58560 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-300.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-300italic.woff2 b/src/assets/fonts/nunito-v26-latin-300italic.woff2 new file mode 100644 index 0000000..1c66c9c Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-300italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-500.woff2 b/src/assets/fonts/nunito-v26-latin-500.woff2 new file mode 100644 index 0000000..7331d3c Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-500.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-500italic.woff2 b/src/assets/fonts/nunito-v26-latin-500italic.woff2 new file mode 100644 index 0000000..376f288 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-500italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-600.woff2 b/src/assets/fonts/nunito-v26-latin-600.woff2 new file mode 100644 index 0000000..7c47892 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-600.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-600italic.woff2 b/src/assets/fonts/nunito-v26-latin-600italic.woff2 new file mode 100644 index 0000000..ffa91b6 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-600italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-700.woff2 b/src/assets/fonts/nunito-v26-latin-700.woff2 new file mode 100644 index 0000000..57c5a6c Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-700.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-700italic.woff2 b/src/assets/fonts/nunito-v26-latin-700italic.woff2 new file mode 100644 index 0000000..94b48f4 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-700italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-800.woff2 b/src/assets/fonts/nunito-v26-latin-800.woff2 new file mode 100644 index 0000000..3e93dfc Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-800.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-800italic.woff2 b/src/assets/fonts/nunito-v26-latin-800italic.woff2 new file mode 100644 index 0000000..9dbd944 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-800italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-900.woff2 b/src/assets/fonts/nunito-v26-latin-900.woff2 new file mode 100644 index 0000000..7d4aa2c Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-900.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-900italic.woff2 b/src/assets/fonts/nunito-v26-latin-900italic.woff2 new file mode 100644 index 0000000..299d78c Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-900italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-italic.woff2 b/src/assets/fonts/nunito-v26-latin-italic.woff2 new file mode 100644 index 0000000..6a05da4 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-italic.woff2 differ diff --git a/src/assets/fonts/nunito-v26-latin-regular.woff2 b/src/assets/fonts/nunito-v26-latin-regular.woff2 new file mode 100644 index 0000000..99439c1 Binary files /dev/null and b/src/assets/fonts/nunito-v26-latin-regular.woff2 differ diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json new file mode 100644 index 0000000..943078a --- /dev/null +++ b/src/assets/i18n/de.json @@ -0,0 +1,291 @@ +{ + "login": { + "header": "Anmeldung", + "infoText": "Wir empfehlen dir, die E-Mail-Adresse zu nutzen, die du bei der Arbeit verwendest.", + "inputField": "beispielname@email.com", + "inputField2": "Passwort", + "midText": "Passwort vergessen?", + "midSeperator": "ODER", + "googleBtn": "Anmeldung mit Google", + "BtnLeft": "Anmelden", + "BtnRight": "Gäste-Login", + "topText": "Neu bei DABubble?", + "topText2": "Konto erstellen", + "errorText": "*Email ist erforderlich.", + "errorText2": "*Passwort ist erforderlich." + }, + + "createAccount": { + "header": "Konto erstellen", + "infoText": "Mit deinem Namen und deiner E-Mail-Adresse hast du dein neues DABubble-Konto.", + "inputField": "Name und Nachname", + "inputField2": "beispielname@email.com", + "inputField3": "Passwort", + "midText": "Ich stimme der", + "midText2": "Datenschutzerklärung", + "midText3": "zu.", + "Btn": "Weiter", + "errorText": "*Name ist erforderlich.", + "errorText2": "*Email ist erforderlich.", + "errorText3": "*Bitte geben Sie ein Passwort ein (mind. 6 Zeichen)." + }, + + "chooseAvatar": { + "header": "Wähle deinen Avatar", + "avatarInfo": "Aus der Liste wählen", + "ownAvatar": "eigenes Bild verwenden", + "avatarBtn": "Datei hochladen", + "Btn": "Weiter" + }, + + "passwordForget": { + "header": "Passwort zurücksetzen", + "infoText": "Bitte geben Sie Ihre E-Mail-Adresse ein.", + "inputfield": "beispielname@email.com", + "infoTextBottom": "Wir senden Ihnen eine E-Mail, Über die Sie Ihr Passwort ändern können.", + "Btn": "E-Mail senden", + "errorText": "*Email ist erforderlich." + }, + + "passwordReset": { + "header": "Passwort zurücksetzen", + "inputfield": "Neues Passwort", + "inputfield2": "Neues Passwort bestätigen", + "Btn": "Passwort ändern", + "errorText": "*Bitte geben Sie ein neus Passwort ein (mind.6 Zeichen).", + "errorText2": "*Die Passwörter stimmen nicht überein." + }, + + "channel-informations": { + "header": "Kanal Name", + "channelInfo": "Beschreibung", + "channelInfo2": "keine Beschreibung.", + "channelMadeBy": "Erstellt von", + "channelErrorText": "*Nur der Ersteller kann den Kanal bearbeiten", + "members": "Mitglieder", + "leave": "Kanal verlassen" + }, + + "channel-msg-box": { + "text": "Die maximale Anzahl an Dateien beträgt 1.", + "placeholder": "Geben Sie Ihre Nachricht ein" + }, + + "info": { + "channelCreate": "Der Kanal wurde von", + "channelCreate2": "am", + "channelCreate3": " erstellt. Das ist der Anfang des Kanals", + "notice": "Dieser Raum ist nur für dich da. Mache dir Notizen, liste deine To-dos auf oder bewahre Links und Dateien griffbereit auf. Du kannst hier auch gerne Dinge mit dir selbst besprechen.", + "talkTo": "Diese Unterhaltung findet nur zwischen", + "talkTo2": "und dir statt." + }, + + "show-channel-member": { + "header": "Kanal Mitglieder", + "addMember": "Mitglieder hinzufügen", + "result": "Keine Ergebnisse", + "add": "hinzufügen" + }, + + "open-send-prv-message": { + "profil": "Profil", + "aktiv": "Aktiv", + "offline": "Offline", + "adress": "E-Mail-Address", + "message": "Nachricht" + }, + + "main-chat": { + "message": "Neue Nachricht", + "placeholder": "An: #Kanal oder @jemanden" + }, + + "edit-msg": { + "save": "Speichern", + "cancel": "Abbrechen" + }, + + "options-menu": { + "delete": "Nachricht löschen", + "edit": "Nachricht bearbeiten" + }, + + "reaction-emojis": { + "react": "haben reagiert.", + "react2": "hat reagiert." + }, + + "single-chat": { + "edit": "(bearbeitet)", + "answer": "Antworten", + "answer2": "Antwort", + "answer3": "Letzte Antwort:", + "answer4": "Antwort..." + }, + + "secondary-chat": { + "thread": "Thema", + "answer": "Antworten" + }, + + "add-new-channel": { + "header": "Kanal erstellen", + "info": "Kanäls dienen ihrem Team zur Kommuniktaion. Am besten sollten sie themenbezogen sein #marketing zum Beispiel.", + "header2": "Kanal-Name", + "required": "(erforderlich)", + "placeholder": "(mind. 6 Buchstaben)", + "placeholder2": "Schreiben Sie hier, welche Themen im Kanal besprochen werden können.", + "description": "Beschreibung", + "optional": "(optional)", + "create": "Erstellen", + "addPeople": "Leute hinzufügen", + "addAll": "Alle Mitglieder hinzufügen von", + "devspace": "Devspace", + "add": "Fügen Sie bestimmte Personen hinzu", + "warning": "Dieser Kanal existiert bereits" + }, + + "sidebar-channels": { + "channel": "Kanäle", + "addChannel": "Kanal hinzufügen" + }, + + "sidebar-direct-messages": { + "messages": "Direktnachrichten", + "members": "Mitgliederliste" + }, + + "sidebar-direct-messages-user": { + "you": "Du" + }, + + "sidebar-toggle": { + "openWorkspace": "Menü öffnen" + }, + + "edit-user-details": { + "profile": "Dein Profil bearbeiten", + "fullName": "Vollständiger Name", + "placeholder": "Ihr Name (min. 3 Buchstaben)", + "placeholder2": "Ihre E-Mail-Adresse", + "email": "E-Mail-Addresse", + "cancel": "Abbrechen", + "save": "Speichern", + "errorMessage": "* Änderungen am Gast Profil sind nicht möglich." + }, + + "edit-user": { + "edit": "bearbeiten", + "email": "E-Mail-Addresse" + }, + + "search-bar": { + "placeholder": "Im Devspace suchen", + "errorMessage": "Keine Übereinstimmung gefunden" + }, + + "search-bar-header": { + "user": "Benutzer", + "channels": "Kanäle", + "thread": "Themen" + }, + + "footer": { + "privatePolice": "Datenschutz", + "imprint": "Impressum" + }, + + "start-header": { + "new": "Neu bei DABubble?", + "create": "Konto erstellen" + }, + + "login-header": { + "profil": "Profil", + "logout": "Ausloggen" + }, + + "user": { + "email": "E-Mail-Addresse", + "message": "Direktnachrichten" + }, + + "imprint": { + "headline": "Imprint", + "tmg": "Angaben gemäß §5 TMG", + "contact": "Kontakt", + "tel": "Telefon", + "mail": "E-Mail", + "disclaimer": "Haftungsausschluss", + "liabilityContentHeadline": "Haftung für Inhalte", + "liabilityContentDescription": "Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.", + "liabilityLinksHeadline": "Haftung für Links", + "liabilityLinksDescription": "Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.", + "copyrightHeadline": "Urheberrecht", + "copyrightDescription": "Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.", + "dataProtectionHeadline": "Datenschutz", + "dataProtectionDescription": "Die Nutzung unserer Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder eMail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben. Wir weisen darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich. Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.", + "sourceText0": "Impressum vom", + "sourceLink0": "Impressum Generator", + "sourceText1": "der", + "sourceLink1": "Kanzlei Hasselbach, Rechtsanwälte für Arbeitsrecht und Familienrecht" + }, + "privacy-policy": { + "headline": "Datenschutzerklärung", + "preambleHeadline": "Präambel", + "preambleDescription": "Mit der folgenden Datenschutzerklärung möchten wir Sie darüber aufklären, welche Arten Ihrer personenbezogenen Daten (nachfolgend auch kurz als 'Daten' bezeichnet) wir zu welchen Zwecken und in welchem Umfang verarbeiten. Die Datenschutzerklärung gilt für alle von uns durchgeführten Verarbeitungen personenbezogener Daten, sowohl im Rahmen der Erbringung unserer Leistungen als auch insbesondere auf unseren Webseiten, in mobilen Applikationen sowie innerhalb externer Onlinepräsenzen, wie z.B. unserer Social-Media-Profile (nachfolgend zusammenfassend bezeichnet als 'Onlineangebot').", + "ContentHeadline": "Inhaltsübersicht", + "Content0": "Präambel", + "Content1": "Verantwortliche", + "Content2": "Übersicht der Verarbeitungen", + "Content3": "Maßgebliche Rechtsgrundlagen", + "Content4": "Sicherheitsmaßnahmen", + "Content5": "Löschung von Daten", + "Content6": "Rechte der betroffenen Personen", + "Content7": "Änderung und Aktualisierung der Datenschutzerklärung", + "Content8": "Begriffsdefinitionen", + "tel": "Telefon", + "mail": "E-Mail", + "Content2Description": "Die nachfolgende Übersicht fasst die Arten der verarbeiteten Daten und die Zwecke ihrer Verarbeitung zusammen und verweist auf die betroffenen Personen.", + "Content2Section0": "Arten der verarbeiteten Daten", + "Content2Section0List": "Kontaktdaten, Inhaltsdaten, Nutzungsdaten, Metadaten, Kommunikationsdaten, Verfahrensdaten.", + "Content2Section1": "Kategorien betroffener Personen", + "Content2Section1List": "Kommunikationspartner", + "Content2Section2": "Zwecke der Verarbeitung", + "Content2Section2List": "Kontaktanfragen und Kommunikation, Verwaltung und Beantwortung von Anfragen, Feedback, Bereitstellung unseres Onlineangebotes und Nutzerfreundlichkeit.", + "Content3Header0": "Maßgebliche Rechtsgrundlagen nach der DSGVO:", + "Content3Description0": "Im Folgenden erhalten Sie eine Übersicht der Rechtsgrundlagen der DSGVO, auf deren Basis wir personenbezogene Daten verarbeiten. Bitte nehmen Sie zur Kenntnis, dass neben den Regelungen der DSGVO nationale Datenschutzvorgaben in Ihrem bzw. unserem Wohn- oder Sitzland gelten können. Sollten ferner im Einzelfall speziellere Rechtsgrundlagen maßgeblich sein, teilen wir Ihnen diese in der Datenschutzerklärung mit.", + "Content3Header1": "Berechtigte Interessen (Art. 6 Abs. 1 S. 1 lit. f) DSGVO:", + "Content3Description1": "Die Verarbeitung ist zur Wahrung der berechtigten Interessen des Verantwortlichen oder eines Dritten erforderlich, sofern nicht die Interessen oder Grundrechte und Grundfreiheiten der betroffenen Person, die den Schutz personenbezogener Daten erfordern, überwiegen.", + "Content3Header2": "Nationale Datenschutzregelungen in Deutschland:", + "Content3Description2": "Zusätzlich zu den Datenschutzregelungen der DSGVO gelten nationale Regelungen zum Datenschutz in Deutschland. Hierzu gehört insbesondere das Gesetz zum Schutz vor Missbrauch personenbezogener Daten bei der Datenverarbeitung (Bundesdatenschutzgesetz - BDSG). Das BDSG enthält insbesondere Spezialregelungen zum Recht auf Auskunft, zum Recht auf Löschung, zum Widerspruchsrecht, zur Verarbeitung besonderer Kategorien personenbezogener Daten, zur Verarbeitung für andere Zwecke und zur Übermittlung sowie automatisierten Entscheidungsfindung im Einzelfall einschließlich Profiling. Ferner können Landesdatenschutzgesetze der einzelnen Bundesländer zur Anwendung gelangen.", + "Content4Description0": "Wir treffen nach Maßgabe der gesetzlichen Vorgaben unter Berücksichtigung des Stands der Technik, der Implementierungskosten und der Art, des Umfangs, der Umstände und der Zwecke der Verarbeitung sowie der unterschiedlichen Eintrittswahrscheinlichkeiten und des Ausmaßes der Bedrohung der Rechte und Freiheiten natürlicher Personen geeignete technische und organisatorische Maßnahmen, um ein dem Risiko angemessenes Schutzniveau zu gewährleisten.", + "Content4Description1": "Zu den Maßnahmen gehören insbesondere die Sicherung der Vertraulichkeit, Integrität und Verfügbarkeit von Daten durch Kontrolle des physischen und elektronischen Zugangs zu den Daten als auch des sie betreffenden Zugriffs, der Eingabe, der Weitergabe, der Sicherung der Verfügbarkeit und ihrer Trennung. Des Weiteren haben wir Verfahren eingerichtet, die eine Wahrnehmung von Betroffenenrechten, die Löschung von Daten und Reaktionen auf die Gefährdung der Daten gewährleisten. Ferner berücksichtigen wir den Schutz personenbezogener Daten bereits bei der Entwicklung bzw. Auswahl von Hardware, Software sowie Verfahren entsprechend dem Prinzip des Datenschutzes, durch Technikgestaltung und durch datenschutzfreundliche Voreinstellungen.", + "Content4Description2": "TLS/SSL-Verschlüsselung (https): Um die Daten der Benutzer, die über unsere Online-Dienste übertragen werden, zu schützen, verwenden wir TLS/SSL-Verschlüsselung. Secure Sockets Layer (SSL) ist die Standardtechnologie zur Sicherung von Internetverbindungen durch Verschlüsselung der zwischen einer Website oder App und einem Browser (oder zwischen zwei Servern) übertragenen Daten. Transport Layer Security (TLS) ist eine aktualisierte und sicherere Version von SSL. Hyper Text Transfer Protocol Secure (HTTPS) wird in der URL angezeigt, wenn eine Website durch ein SSL/TLS-Zertifikat gesichert ist.", + "Content5Description": "Die von uns verarbeiteten Daten werden nach Maßgabe der gesetzlichen Vorgaben gelöscht, sobald deren zur Verarbeitung erlaubten Einwilligungen widerrufen werden oder sonstige Erlaubnisse entfallen (z.B. wenn der Zweck der Verarbeitung dieser Daten entfallen ist oder sie für den Zweck nicht erforderlich sind). Sofern die Daten nicht gelöscht werden, weil sie für andere und gesetzlich zulässige Zwecke erforderlich sind, wird deren Verarbeitung auf diese Zwecke beschränkt. D.h., die Daten werden gesperrt und nicht für andere Zwecke verarbeitet. Das gilt z.B. für Daten, die aus handels- oder steuerrechtlichen Gründen aufbewahrt werden müssen oder deren Speicherung zur Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen oder zum Schutz der Rechte einer anderen natürlichen oder juristischen Person erforderlich ist. Unsere Datenschutzhinweise können ferner weitere Angaben zu der Aufbewahrung und Löschung von Daten beinhalten, die für die jeweiligen Verarbeitungen vorrangig gelten.", + "Content6Description0": "Rechte der betroffenen Personen aus der DSGVO: Ihnen stehen als Betroffene nach der DSGVO verschiedene Rechte zu, die sich insbesondere aus Art. 15 bis 21 DSGVO ergeben:", + "Content6Description1": "Widerspruchsrecht: Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen Situation ergeben, jederzeit gegen die Verarbeitung der Sie betreffenden personenbezogenen Daten, die aufgrund von Art. 6 Abs. 1 lit. e oder f DSGVO erfolgt, Widerspruch einzulegen; dies gilt auch für ein auf diese Bestimmungen gestütztes Profiling. Werden die Sie betreffenden personenbezogenen Daten verarbeitet, um Direktwerbung zu betreiben, haben Sie das Recht, jederzeit Widerspruch gegen die Verarbeitung der Sie betreffenden personenbezogenen Daten zum Zwecke derartiger Werbung einzulegen; dies gilt auch für das Profiling, soweit es mit solcher Direktwerbung in Verbindung steht.", + "Content6Section0": "Widerrufsrecht bei Einwilligungen:", + "Content6Section0List": "Sie haben das Recht,erteilte Einwilligungen jederzeit zu widerrufen.", + "Content6Section1": "Auskunftsrecht:", + "Content6Section1List": "Sie haben das Recht, eine Bestätigung darüber zu verlangen, ob betreffende Daten verarbeitet werden und auf Auskunft über diese Daten sowie auf weitere Informationen und Kopie der Daten entsprechend den gesetzlichen Vorgaben.", + "Content6Section2": "Recht auf Berichtigung:", + "Content6Section2List": "Sie haben entsprechend den gesetzlichen Vorgaben das Recht, die Vervollständigung der Sie betreffenden Daten oder die Berichtigung der Sie betreffenden unrichtigen Daten zu verlangen.", + "Content6Section3": "Recht auf Löschung und Einschränkung der Verarbeitung:", + "Content6Section3List": "Sie haben nach Maßgabe der gesetzlichen Vorgaben das Recht, zu verlangen, dass Sie betreffende Daten unverzüglich gelöscht werden, bzw. alternativ nach Maßgabe der gesetzlichen Vorgaben eine Einschränkung der Verarbeitung der Daten zu verlangen.", + "Content6Section4": "Recht auf Datenübertragbarkeit:", + "Content6Section4List": "Sie haben das Recht, Sie betreffende Daten, die Sie uns bereitgestellt haben, nach Maßgabe der gesetzlichen Vorgaben in einem strukturierten, gängigen und maschinenlesbaren Format zu erhalten oder deren Übermittlung an einen anderen Verantwortlichen zu fordern.", + "Content6Section5": "Beschwerde bei Aufsichtsbehörde:", + "Content6Section5List": "Sie haben unbeschadet eines anderweitigen verwaltungsrechtlichen oder gerichtlichen Rechtsbehelfs das Recht auf Beschwerde bei einer Aufsichtsbehörde, insbesondere in dem Mitgliedstaat ihres gewöhnlichen Aufenthaltsorts, ihres Arbeitsplatzes oder des Orts des mutmaßlichen Verstoßes, wenn Sie der Ansicht sind, dass die Verarbeitung der Sie betreffenden personenbezogenen Daten gegen die Vorgaben der DSGVO verstößt.", + "Content7Description0": "Wir bitten Sie, sich regelmäßig über den Inhalt unserer Datenschutzerklärung zu informieren. Wir passen die Datenschutzerklärung an, sobald die Änderungen der von uns durchgeführten Datenverarbeitungen dies erforderlich machen. Wir informieren Sie, sobald durch die Änderungen eine Mitwirkungshandlung Ihrerseits (z.B. Einwilligung) oder eine sonstige individuelle Benachrichtigung erforderlich wird.", + "Content7Description1": "Sofern wir in dieser Datenschutzerklärung Adressen und Kontaktinformationen von Unternehmen und Organisationen angeben, bitten wir zu beachten, dass die Adressen sich über die Zeit ändern können und bitten die Angaben vor Kontaktaufnahme zu prüfen.", + "Content8Description0": "In diesem Abschnitt erhalten Sie eine Übersicht über die in dieser Datenschutzerklärung verwendeten Begrifflichkeiten. Soweit die Begrifflichkeiten gesetzlich definiert sind, gelten deren gesetzliche Definitionen. Die nachfolgenden Erläuterungen sollen dagegen vor allem dem Verständnis dienen.", + "Content8Section0": "Personenbezogene Daten:", + "Content8Section0List": "'Personenbezogene Daten' sind alle Informationen, die sich auf eine identifizierte oder identifizierbare natürliche Person (im Folgenden 'betroffene Person') beziehen; als identifizierbar wird eine natürliche Person angesehen, die direkt oder indirekt, insbesondere mittels Zuordnung zu einer Kennung wie einem Namen, zu einer Kennnummer, zu Standortdaten, zu einer Online-Kennung (z. B. Cookie) oder zu einem oder mehreren besonderen Merkmalen identifiziert werden kann, die Ausdruck der physischen, physiologischen, genetischen, psychischen, wirtschaftlichen, kulturellen oder sozialen Identität dieser natürlichen Person sind.", + "Content8Section1": "Verantwortlicher:", + "Content8Section1List": "Als 'Verantwortlicher' wird die natürliche oder juristische Person, Behörde, Einrichtung oder andere Stelle, die allein oder gemeinsam mit anderen über die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten entscheidet, bezeichnet.", + "Content8Section2": "Verarbeitung", + "Content8Section2List": "'Verarbeitung' ist jeder mit oder ohne Hilfe automatisierter Verfahren ausgeführte Vorgang oder jede solche Vorgangsreihe im Zusammenhang mit personenbezogenen Daten. Der Begriff reicht weit und umfasst praktisch jeden Umgang mit Daten, sei es das Erheben, das Auswerten, das Speichern, das Übermitteln oder das Löschen.", + "sourceText": "Erstellt mit kostenlosem Datenschutz-Generator.de von Dr. Thomas Schwenke" + } +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json new file mode 100644 index 0000000..b4024ae --- /dev/null +++ b/src/assets/i18n/en.json @@ -0,0 +1,292 @@ +{ + "login": { + "header": "Login", + "infoText": "We recommend using the email address you use at work.", + "inputField": "example.name@email.com", + "inputField2": "Password", + "midText": "Forgot password?", + "midSeperator": "OR", + "googleBtn": "Sign in with Google", + "BtnLeft": "Login", + "BtnRight": "Guest Login", + "topText": "New to DABubble?", + "topText2": "Create account", + "errorText": "*Email is required.", + "errorText2": "*Password is required." + }, + + "createAccount": { + "header": "Create Account", + "infoText": "With your name and email address, you have your new DABubble account.", + "inputField": "First and Last Name", + "inputField2": "example.name@email.com", + "inputField3": "Password", + "midText": "I agree to the", + "midText2": "Privacy Policy", + "midText3": ".", + "Btn": "Continue", + "errorText": "*Name is required.", + "errorText2": "*Email is required.", + "errorText3": "*Please enter a password (at least 6 characters)." + }, + + "chooseAvatar": { + "header": "Choose your Avatar", + "avatarInfo": "Choose from the list", + "ownAvatar": "use own picture", + "avatarBtn": "Upload file", + "Btn": "Continue" + }, + + "passwordForget": { + "header": "Reset Password", + "infoText": "Please enter your email address.", + "inputfield": "example.name@email.com", + "infoTextBottom": "We will send you an email to change your password.", + "Btn": "Send Email", + "errorText": "*Email is required." + }, + + "passwordReset": { + "header": "Reset Password", + "inputfield": "New Password", + "inputfield2": "Confirm New Password", + "Btn": "Change Password", + "errorText": "*Please enter a new password (at least 6 characters).", + "errorText2": "*The passwords do not match." + }, + + "channel-informations": { + "header": "Channel Name", + "channelInfo": "Description", + "channelInfo2": "no description.", + "channelMadeBy": "Created by", + "channelErrorText": "*Only the creator can edit the channel", + "members": "Members", + "leave": "Leave Channel" + }, + + "channel-msg-box": { + "text": "The maximum number of files is 1.", + "placeholder": "Enter your message" + }, + + "info": { + "channelCreate": "The channel was created by", + "channelCreate2": "on", + "channelCreate3": ". This is the beginning of the channel", + "notice": "This space is just for you. Make notes, list your to-dos, or keep links and files handy. You can also talk things over with yourself here.", + "talkTo": "This conversation is just between", + "talkTo2": "and you." + }, + + "show-channel-member": { + "header": "Channel Members", + "addMember": "Add Members", + "result": "No results", + "add": "add" + }, + + "open-send-prv-message": { + "profil": "Profile", + "aktiv": "Active", + "offline": "Offline", + "adress": "Email Address", + "message": "Message" + }, + + "main-chat": { + "message": "New Message", + "placeholder": "To: #channel or @someone" + }, + + "edit-msg": { + "save": "Save", + "cancel": "Cancel" + }, + + "options-menu": { + "delete": "Delete message", + "edit": "Edit message" + }, + + "reaction-emojis": { + "react": "have reacted.", + "react2": "has reacted." + }, + + "single-chat": { + "edit": "(edited)", + "answer": "Replys", + "answer2": "Reply", + "answer3": "Last reply:", + "answer4": "Reply..." + }, + + "secondary-chat": { + "thread": "Thread", + "answer": "Reply" + }, + + "add-new-channel": { + "header": "Create Channel", + "info": "Channels serve your team for communication. They should be topic-related, e.g., #marketing.", + "header2": "Channel Name", + "required": "(required)", + "placeholder": "(at least 6 characters)", + "placeholder2": "Write here what topics can be discussed in the channel.", + "description": "Description", + "optional": "(optional)", + "create": "Create", + "addPeople": "Add people", + "addAll": "Add all members from", + "devspace": "Devspace", + "add": "Add specific people", + "warning": "This channel already exists" + }, + + "sidebar-channels": { + "channel": "Channels", + "addChannel": "Add Channel" + }, + + "sidebar-direct-messages": { + "messages": "Direct messages", + "members": "List of members" + }, + + "sidebar-direct-messages-user": { + "you": "You" + }, + + "sidebar-toggle": { + "openWorkspace": "Open Menu" + }, + + "edit-user-details": { + "profile": "Edit Your Profile", + "fullName": "Full Name", + "placeholder": "Your name (min. 3 letters)", + "placeholder2": "Your email address", + "email": "Email Address", + "cancel": "Cancel", + "save": "Save", + "errorMessage": "* Changes to the guest profile are not possible." + }, + + "edit-user": { + "edit": "edit", + "email": "Email Address" + }, + + "search-bar": { + "placeholder": "Search in Devspace", + "errorMessage": "No match found" + }, + + "search-bar-header": { + "user": "Users", + "channels": "Channels", + "thread": "Threads" + }, + + "footer": { + "privatePolice": "Privacy Policy", + "imprint": "Legal Notice" + }, + + "start-header": { + "new": "New to DABubble?", + "create": "Create Account" + }, + + "login-header": { + "profil": "Profile", + "logout": "Log out" + }, + + "user": { + "email": "Email Address", + "message": "Direct Messages" + }, + + "imprint": { + "headline": "Imprint", + "tmg": "Information according to §5 TMG", + "contact": "Contact", + "tel": "Telephone", + "mail": "Mail", + "disclaimer": "Disclaimer", + "liabilityContentHeadline": "Liability for content", + "liabilityContentDescription": "The contents of our pages were created with the greatest care. However, we cannot assume any liability for the accuracy, completeness and topicality of the content. As a service provider, we are responsible for our own content on these pages in accordance with § 7 para. 1 TMG (German Telemedia Act) and general laws. According to §§ 8 to 10 TMG, however, we as a service provider are not obliged to monitor transmitted or stored third-party information or to investigate circumstances that indicate illegal activity. Obligations to remove or block the use of information in accordance with general legislation remain unaffected by this. However, liability in this respect is only possible from the time of knowledge of a specific infringement. As soon as we become aware of such infringements, we will remove this content immediately.", + "liabilityLinksHeadline": "Liability for links", + "liabilityLinksDescription": "Our website contains links to external third-party websites over whose content we have no influence. Therefore, we cannot accept any liability for this third-party content. The respective provider or operator of the pages is always responsible for the content of the linked pages. The linked pages were checked for possible legal violations at the time of linking. Illegal content was not recognizable at the time of linking. However, permanent monitoring of the content of the linked pages is not reasonable without concrete evidence of an infringement. If we become aware of any legal infringements, we will remove such links immediately.", + "copyrightHeadline": "Copyright", + "copyrightDescription": "The content and works created by the site operators on these pages are subject to German copyright law. Duplication, processing, distribution and any form of commercialization of such material beyond the scope of the copyright law shall require the prior written consent of its respective author or creator. Downloads and copies of this site are only permitted for private, non-commercial use. Insofar as the content on this site was not created by the operator, the copyrights of third parties are respected. In particular, third-party content is identified as such. Should you nevertheless become aware of a copyright infringement, please inform us accordingly. If we become aware of any infringements, we will remove such content immediately.", + "dataProtectionHeadline": "Data protection", + "dataProtectionDescription": "The use of our website is generally possible without providing personal data. Insofar as personal data (e.g. name, address or e-mail addresses) is collected on our pages, this is always done on a voluntary basis as far as possible. This data will not be passed on to third parties without your express consent. We would like to point out that data transmission over the Internet (e.g. when communicating by e-mail) may be subject to security vulnerabilities. Complete protection of data against access by third parties is not possible, and we hereby expressly prohibit the use of contact data published in the context of the legal notice obligation by third parties for sending unsolicited advertising and information material. The operators of this website expressly reserve the right to take legal action in the event of the unsolicited sending of advertising information, such as spam e-mails.", + "sourceText0": "Imprint of the", + "sourceLink0": "imprint generator", + "sourceText1": "of the", + "sourceLink1": "law firm Hasselbach, lawyers for labor law and family law" + }, + + "privacy-policy": { + "headline": "Privacy policy", + "preambleHeadline": "Preamble", + "preambleDescription": "With the following privacy policy, we would like to inform you about which types of your personal data (hereinafter also referred to as 'data') we process, for what purposes and to what extent. The privacy policy applies to all processing of personal data carried out by us, both in the context of the provision of our services and in particular on our websites, in mobile applications and within external online presences, such as our social media profiles (hereinafter collectively referred to as 'online offer').", + "ContentHeadline": "Table of contents", + "Content0": "Preamble", + "Content1": "Person responsible", + "Content2": "Overview of processing", + "Content3": "Relevant legal bases", + "Content4": "Security measures", + "Content5": "Deletion of data", + "Content6": "Rights of the data subjects", + "Content7": "Amendment and updating of the privacy policy", + "Content8": "Definitions of terms", + "tel": "Telephone", + "mail": "Mail", + "Content2Description": "The following overview summarizes the types of data processed and the purposes of their processing and refers to the data subjects.", + "Content2Section0": "Types of data processed", + "Content2Section0List": "Contact data, content data, usage data, metadata, communication data, process data.", + "Content2Section1": "Categories of affected persons", + "Content2Section1List": "Communication partner", + "Content2Section2": "Purposes of the processing", + "Content2Section2List": "Contact requests and communication, managing and responding to requests, feedback, providing our online services and user-friendliness.", + "Content3Header0": "Relevant legal bases according to the GDPR:", + "Content3Description0": "Below you will find an overview of the legal bases of the GDPR on the basis of which we process personal data. Please note that in addition to the provisions of the GDPR, national data protection regulations may apply in your or our country of residence or domicile. Should more specific legal bases also apply in individual cases, we will inform you of these in the privacy policy.", + "Content3Header1": "Legitimate interests (Art. 6 para. 1 sentence 1 lit. f) GDPR:", + "Content3Description1": "Processing is necessary for the purposes of the legitimate interests pursued by the controller or by a third party, except where such interests are overridden by the interests or fundamental rights and freedoms of the data subject which require protection of personal data.", + "Content3Header2": "National data protection regulations in Germany:", + "Content3Description2": "In addition to the data protection regulations of the GDPR, national data protection regulations apply in Germany. These include, in particular, the Act on the Protection against Misuse of Personal Data in Data Processing (Federal Data Protection Act - BDSG). In particular, the BDSG contains special regulations on the right to information, the right to erasure, the right to object, the processing of special categories of personal data, processing for other purposes and transmission as well as automated decision-making in individual cases, including profiling. The data protection laws of the individual federal states may also apply.", + "Content4Description0": "We take appropriate technical and organizational measures in accordance with the legal requirements, taking into account the state of the art, the implementation costs and the nature, scope, circumstances and purposes of the processing as well as the different probabilities of occurrence and the extent of the threat to the rights and freedoms of natural persons, in order to ensure a level of protection appropriate to the risk.", + "Content4Description1": "The measures include, in particular, safeguarding the confidentiality, integrity and availability of data by controlling physical and electronic access to the data as well as the access, input, disclosure, safeguarding of availability and its separation. Furthermore, we have established procedures that ensure the exercise of data subject rights, the deletion of data and responses to data threats. Furthermore, we already take the protection of personal data into account during the development or selection of hardware, software and processes in accordance with the principle of data protection, through technology design and through data protection-friendly default settings.", + "Content4Description2": "TLS/SSL encryption (https): To protect user data transmitted via our online services, we use TLS/SSL encryption. Secure Sockets Layer (SSL) is the standard technology for securing Internet connections by encrypting the data transmitted between a website or app and a browser (or between two servers). Transport Layer Security (TLS) is an updated and more secure version of SSL. Hyper Text Transfer Protocol Secure (HTTPS) is displayed in the URL when a website is secured by an SSL/TLS certificate.", + "Content5Description": "The data processed by us will be deleted in accordance with the legal requirements as soon as the consent given for processing is revoked or other permissions no longer apply (e.g. if the purpose for processing this data no longer applies or it is not required for the purpose). If the data is not deleted because it is required for other and legally permissible purposes, its processing is restricted to these purposes. This means that the data is blocked and not processed for other purposes. This applies, for example, to data that must be retained for commercial or tax law reasons or whose storage is necessary for the assertion, exercise or defense of legal claims or to protect the rights of another natural or legal person. Our data protection notices may also contain further information on the retention and deletion of data, which take priority for the respective processing operations.", + "Content6Description0": "Rights of data subjects under the GDPR: As a data subject, you are entitled to various rights under the GDPR, which arise in particular from Art. 15 to 21 GDPR:", + "Content6Description1": "Right to object: You have the right to object, on grounds relating to your particular situation, at any time to processing of personal data concerning you which is based on point (e) or (f) of Article 6(1) GDPR, including profiling based on those provisions. If the personal data concerning you are processed for direct marketing purposes, you have the right to object at any time to the processing of personal data concerning you for such marketing, which includes profiling to the extent that it is related to such direct marketing.", + "Content6Section0": "Right to withdraw consent:", + "Content6Section0List": "You have the right to withdraw your consent at any time.", + "Content6Section1": "Right to information:", + "Content6Section1List": "You have the right to request confirmation as to whether the data in question is being processed and to request information about this data as well as further information and a copy of the data in accordance with the legal requirements.", + "Content6Section2": "Right to rectification:", + "Content6Section2List": "In accordance with the legal requirements, you have the right to request the completion of data concerning you or the correction of incorrect data concerning you.", + "Content6Section3": "Right to erasure and restriction of processing:", + "Content6Section3List": "In accordance with the legal requirements, you have the right to demand that data concerning you be deleted immediately or, alternatively, to demand that the processing of the data be restricted in accordance with the legal requirements.", + "Content6Section4": "Right to data portability:", + "Content6Section4List": "You have the right to receive the data concerning you, which you have provided to us, in a structured, commonly used and machine-readable format in accordance with the legal requirements or to request its transmission to another controller.", + "Content6Section5": "Complaint to the supervisory authority:", + "Content6Section6List": "Without prejudice to any other administrative or judicial remedy, you have the right to lodge a complaint with a supervisory authority, in particular in the Member State of your habitual residence, place of work or place of the alleged infringement if you consider that the processing of personal data relating to you infringes the provisions of the GDPR.", + "Content7Description0": "We ask you to inform yourself regularly about the content of our privacy policy. We will adapt the privacy policy as soon as changes to the data processing carried out by us make this necessary. We will inform you as soon as the changes require an act of cooperation on your part (e.g. consent) or other individual notification.", + "Content7Description1": "If we provide addresses and contact information of companies and organizations in this privacy policy, please note that the addresses may change over time and please check the information before contacting us.", + "Content8Description0": "This section provides you with an overview of the terms used in this privacy policy. Insofar as the terms are defined by law, their legal definitions apply. The following explanations, on the other hand, are primarily intended to aid understanding.", + "Content8Section0": "Personal data:", + "Content8Section0List": "'Personal data' means any information relating to an identified or identifiable natural person (hereinafter referred to as 'data subject'); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier (e.g. a cookie) or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person.", + "Content8Section1": "Responsible person:", + "Content8Section1List": "The 'controller' is the natural or legal person, public authority, agency or other body which, alone or jointly with others, determines the purposes and means of the processing of personal data.", + "Content8Section2": "Processing", + "Content8Section2List": "'Processing' means any operation or set of operations which is performed on personal data, whether or not by automated means. The term is broad and covers practically every handling of data, be it collection, analysis, storage, transmission or deletion.", + "sourceText": "Created with free Datenschutz-Generator.de by Dr. Thomas Schwenke" + } +} diff --git a/src/assets/img/add-reaction.svg b/src/assets/img/add-reaction.svg new file mode 100644 index 0000000..2bdb672 --- /dev/null +++ b/src/assets/img/add-reaction.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/img/add.svg b/src/assets/img/add.svg new file mode 100644 index 0000000..3b0f99c --- /dev/null +++ b/src/assets/img/add.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/addIcon.svg b/src/assets/img/addIcon.svg new file mode 100644 index 0000000..0f84688 --- /dev/null +++ b/src/assets/img/addIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/addPerson.svg b/src/assets/img/addPerson.svg new file mode 100644 index 0000000..d929391 --- /dev/null +++ b/src/assets/img/addPerson.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/answer.svg b/src/assets/img/answer.svg new file mode 100644 index 0000000..958f90b --- /dev/null +++ b/src/assets/img/answer.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/arrowLeft.png b/src/assets/img/arrowLeft.png new file mode 100644 index 0000000..28b2a92 Binary files /dev/null and b/src/assets/img/arrowLeft.png differ diff --git a/src/assets/img/arrowRight.png b/src/assets/img/arrowRight.png new file mode 100644 index 0000000..8b60973 Binary files /dev/null and b/src/assets/img/arrowRight.png differ diff --git a/src/assets/img/atIcon.svg b/src/assets/img/atIcon.svg new file mode 100644 index 0000000..6cef6b6 --- /dev/null +++ b/src/assets/img/atIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/attachments/doc.png b/src/assets/img/attachments/doc.png new file mode 100644 index 0000000..4c2ef87 Binary files /dev/null and b/src/assets/img/attachments/doc.png differ diff --git a/src/assets/img/attachments/pdf.png b/src/assets/img/attachments/pdf.png new file mode 100644 index 0000000..b23c51e Binary files /dev/null and b/src/assets/img/attachments/pdf.png differ diff --git a/src/assets/img/attachments/txt.png b/src/assets/img/attachments/txt.png new file mode 100644 index 0000000..788429c Binary files /dev/null and b/src/assets/img/attachments/txt.png differ diff --git a/src/assets/img/charater1.svg b/src/assets/img/charater1.svg new file mode 100644 index 0000000..3b12de3 --- /dev/null +++ b/src/assets/img/charater1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/clap-hands.svg b/src/assets/img/clap-hands.svg new file mode 100644 index 0000000..8f647e8 --- /dev/null +++ b/src/assets/img/clap-hands.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/img/closeIcon.svg b/src/assets/img/closeIcon.svg new file mode 100644 index 0000000..8ddba0c --- /dev/null +++ b/src/assets/img/closeIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/documentIcon.svg b/src/assets/img/documentIcon.svg new file mode 100644 index 0000000..309a4f5 --- /dev/null +++ b/src/assets/img/documentIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/hashtag.svg b/src/assets/img/hashtag.svg new file mode 100644 index 0000000..933d9a6 --- /dev/null +++ b/src/assets/img/hashtag.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/home-icon.svg b/src/assets/img/home-icon.svg new file mode 100644 index 0000000..4413eb3 --- /dev/null +++ b/src/assets/img/home-icon.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/imgIcon.svg b/src/assets/img/imgIcon.svg new file mode 100644 index 0000000..0e7c11d --- /dev/null +++ b/src/assets/img/imgIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/keyboardArrowDown.svg b/src/assets/img/keyboardArrowDown.svg new file mode 100644 index 0000000..16e6757 --- /dev/null +++ b/src/assets/img/keyboardArrowDown.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/language.svg b/src/assets/img/language.svg new file mode 100644 index 0000000..3af2272 --- /dev/null +++ b/src/assets/img/language.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/login/arrow-back.png b/src/assets/img/login/arrow-back.png new file mode 100644 index 0000000..04f4939 Binary files /dev/null and b/src/assets/img/login/arrow-back.png differ diff --git a/src/assets/img/login/arrow-back.svg b/src/assets/img/login/arrow-back.svg new file mode 100644 index 0000000..9c2e18b --- /dev/null +++ b/src/assets/img/login/arrow-back.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/img/login/box-checked-hover.png b/src/assets/img/login/box-checked-hover.png new file mode 100644 index 0000000..4b6e426 Binary files /dev/null and b/src/assets/img/login/box-checked-hover.png differ diff --git a/src/assets/img/login/box-checked.png b/src/assets/img/login/box-checked.png new file mode 100644 index 0000000..a3db823 Binary files /dev/null and b/src/assets/img/login/box-checked.png differ diff --git a/src/assets/img/login/box-hover.png b/src/assets/img/login/box-hover.png new file mode 100644 index 0000000..5480582 Binary files /dev/null and b/src/assets/img/login/box-hover.png differ diff --git a/src/assets/img/login/box.png b/src/assets/img/login/box.png new file mode 100644 index 0000000..490ee18 Binary files /dev/null and b/src/assets/img/login/box.png differ diff --git a/src/assets/img/login/close-eye.svg b/src/assets/img/login/close-eye.svg new file mode 100644 index 0000000..d4a6ec4 --- /dev/null +++ b/src/assets/img/login/close-eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/login/email-send-btn.svg b/src/assets/img/login/email-send-btn.svg new file mode 100644 index 0000000..3df9c32 --- /dev/null +++ b/src/assets/img/login/email-send-btn.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/login/google.svg b/src/assets/img/login/google.svg new file mode 100644 index 0000000..6b8522d --- /dev/null +++ b/src/assets/img/login/google.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/img/login/lock.png b/src/assets/img/login/lock.png new file mode 100644 index 0000000..07ce7fb Binary files /dev/null and b/src/assets/img/login/lock.png differ diff --git a/src/assets/img/login/logo-animation.svg b/src/assets/img/login/logo-animation.svg new file mode 100644 index 0000000..d784a71 --- /dev/null +++ b/src/assets/img/login/logo-animation.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/login/logo.png b/src/assets/img/login/logo.png new file mode 100644 index 0000000..286c45a Binary files /dev/null and b/src/assets/img/login/logo.png differ diff --git a/src/assets/img/login/logo.svg b/src/assets/img/login/logo.svg new file mode 100644 index 0000000..323d398 --- /dev/null +++ b/src/assets/img/login/logo.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/login/mail.png b/src/assets/img/login/mail.png new file mode 100644 index 0000000..6a68e5d Binary files /dev/null and b/src/assets/img/login/mail.png differ diff --git a/src/assets/img/login/open-eye.svg b/src/assets/img/login/open-eye.svg new file mode 100644 index 0000000..d136657 --- /dev/null +++ b/src/assets/img/login/open-eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/login/person-filled.png b/src/assets/img/login/person-filled.png new file mode 100644 index 0000000..d96bde8 Binary files /dev/null and b/src/assets/img/login/person-filled.png differ diff --git a/src/assets/img/mail-icon.svg b/src/assets/img/mail-icon.svg new file mode 100644 index 0000000..7190a58 --- /dev/null +++ b/src/assets/img/mail-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/img/mail-iconBlack.svg b/src/assets/img/mail-iconBlack.svg new file mode 100644 index 0000000..d614709 --- /dev/null +++ b/src/assets/img/mail-iconBlack.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/messageIcon.svg b/src/assets/img/messageIcon.svg new file mode 100644 index 0000000..07f2128 --- /dev/null +++ b/src/assets/img/messageIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/more-vertical.svg b/src/assets/img/more-vertical.svg new file mode 100644 index 0000000..17e9933 --- /dev/null +++ b/src/assets/img/more-vertical.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/mp3Icon.svg b/src/assets/img/mp3Icon.svg new file mode 100644 index 0000000..b10ad19 --- /dev/null +++ b/src/assets/img/mp3Icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/offlineRing.svg b/src/assets/img/offlineRing.svg new file mode 100644 index 0000000..a2a61ea --- /dev/null +++ b/src/assets/img/offlineRing.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/okay.svg b/src/assets/img/okay.svg new file mode 100644 index 0000000..ca62613 --- /dev/null +++ b/src/assets/img/okay.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/img/onlineRing.svg b/src/assets/img/onlineRing.svg new file mode 100644 index 0000000..ec72154 --- /dev/null +++ b/src/assets/img/onlineRing.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/pdfIcon.svg b/src/assets/img/pdfIcon.svg new file mode 100644 index 0000000..5217155 --- /dev/null +++ b/src/assets/img/pdfIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/pencil.svg b/src/assets/img/pencil.svg new file mode 100644 index 0000000..9561134 --- /dev/null +++ b/src/assets/img/pencil.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/personCircle.svg b/src/assets/img/personCircle.svg new file mode 100644 index 0000000..cda6c9f --- /dev/null +++ b/src/assets/img/personCircle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/radioButtonChecked.svg b/src/assets/img/radioButtonChecked.svg new file mode 100644 index 0000000..559f65a --- /dev/null +++ b/src/assets/img/radioButtonChecked.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/img/radioButtonUnchecked.svg b/src/assets/img/radioButtonUnchecked.svg new file mode 100644 index 0000000..e05a58e --- /dev/null +++ b/src/assets/img/radioButtonUnchecked.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/img/save.svg b/src/assets/img/save.svg new file mode 100644 index 0000000..65c1201 --- /dev/null +++ b/src/assets/img/save.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/search-icon.svg b/src/assets/img/search-icon.svg new file mode 100644 index 0000000..cf42f23 --- /dev/null +++ b/src/assets/img/search-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/sendIcon.svg b/src/assets/img/sendIcon.svg new file mode 100644 index 0000000..33165bb --- /dev/null +++ b/src/assets/img/sendIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/sidebar/account-circle.svg b/src/assets/img/sidebar/account-circle.svg new file mode 100644 index 0000000..5ce57bd --- /dev/null +++ b/src/assets/img/sidebar/account-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/sidebar/add-circle.svg b/src/assets/img/sidebar/add-circle.svg new file mode 100644 index 0000000..3026a4b --- /dev/null +++ b/src/assets/img/sidebar/add-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/sidebar/arrow-drop-down.svg b/src/assets/img/sidebar/arrow-drop-down.svg new file mode 100644 index 0000000..d1183f1 --- /dev/null +++ b/src/assets/img/sidebar/arrow-drop-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/sidebar/arrow_right.png b/src/assets/img/sidebar/arrow_right.png new file mode 100644 index 0000000..eb0d339 Binary files /dev/null and b/src/assets/img/sidebar/arrow_right.png differ diff --git a/src/assets/img/sidebar/bubbles.svg b/src/assets/img/sidebar/bubbles.svg new file mode 100644 index 0000000..88353e2 --- /dev/null +++ b/src/assets/img/sidebar/bubbles.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/img/sidebar/new-chat.svg b/src/assets/img/sidebar/new-chat.svg new file mode 100644 index 0000000..e41d9f1 --- /dev/null +++ b/src/assets/img/sidebar/new-chat.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/img/sidebar/toggle.svg b/src/assets/img/sidebar/toggle.svg new file mode 100644 index 0000000..0c14421 --- /dev/null +++ b/src/assets/img/sidebar/toggle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/img/sidebar/workspace-logo.svg b/src/assets/img/sidebar/workspace-logo.svg new file mode 100644 index 0000000..6bc3c4a --- /dev/null +++ b/src/assets/img/sidebar/workspace-logo.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/smileIcon.svg b/src/assets/img/smileIcon.svg new file mode 100644 index 0000000..0023ed5 --- /dev/null +++ b/src/assets/img/smileIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/user-icons/female-1.svg b/src/assets/img/user-icons/female-1.svg new file mode 100644 index 0000000..5934159 --- /dev/null +++ b/src/assets/img/user-icons/female-1.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/user-icons/female-2.svg b/src/assets/img/user-icons/female-2.svg new file mode 100644 index 0000000..48977b2 --- /dev/null +++ b/src/assets/img/user-icons/female-2.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/user-icons/guest.svg b/src/assets/img/user-icons/guest.svg new file mode 100644 index 0000000..4a942e7 --- /dev/null +++ b/src/assets/img/user-icons/guest.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/img/user-icons/male-1.svg b/src/assets/img/user-icons/male-1.svg new file mode 100644 index 0000000..57f5857 --- /dev/null +++ b/src/assets/img/user-icons/male-1.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/img/user-icons/male-2.svg b/src/assets/img/user-icons/male-2.svg new file mode 100644 index 0000000..54d7880 --- /dev/null +++ b/src/assets/img/user-icons/male-2.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/user-icons/male-3.svg b/src/assets/img/user-icons/male-3.svg new file mode 100644 index 0000000..900ee65 --- /dev/null +++ b/src/assets/img/user-icons/male-3.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/user-icons/male-4.svg b/src/assets/img/user-icons/male-4.svg new file mode 100644 index 0000000..cae6455 --- /dev/null +++ b/src/assets/img/user-icons/male-4.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/verticalLine.svg b/src/assets/img/verticalLine.svg new file mode 100644 index 0000000..ca95de9 --- /dev/null +++ b/src/assets/img/verticalLine.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/videoIcon.svg b/src/assets/img/videoIcon.svg new file mode 100644 index 0000000..9c3d73e --- /dev/null +++ b/src/assets/img/videoIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 0000000..13ec3f1 Binary files /dev/null and b/src/favicon.ico differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..0d6cb97 --- /dev/null +++ b/src/index.html @@ -0,0 +1,21 @@ + + + + + DABubble + + + + + + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..35b00f3 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, appConfig) + .catch((err) => console.error(err)); diff --git a/src/styles.scss b/src/styles.scss new file mode 100644 index 0000000..8dc6995 --- /dev/null +++ b/src/styles.scss @@ -0,0 +1,352 @@ +$RESPONSIVE_THRESHOLD_MOBILE380px: 380px; +$RESPONSIVE_THRESHOLD_MOBILE: 600px; +$RESPONSIVE_THRESHOLD: 1300px; +$RESPONSIVE_THRESHOLD_MAX: 1900px; +$RESPONSIVE_THRESHOLD_SEARCHBAR: 1100px; + +* { + margin: 0; + font-family: "Nunito", sans-serif; +} + +body { + overflow-x: hidden; + background-color: #eceefe; +} + +@mixin displayFlex($d: flex, $j: center, $a: center, $g: 0) { + display: $d; + justify-content: $j; + align-items: $a; + gap: $g; +} + +.dBlock { + display: block; +} + +.dNone { + display: none; +} + +.fontNunito { + font-family: "Nunito"; +} + +.fontNunitoSans { + font-family: "Nunito Sans"; +} + +/* nunito-200 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 200; + src: url("./assets/fonts/nunito-v26-latin-200.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-200italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 200; + src: url("./assets/fonts/nunito-v26-latin-200italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-300 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 300; + src: url("./assets/fonts/nunito-v26-latin-300.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-300italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 300; + src: url("./assets/fonts/nunito-v26-latin-300italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-regular - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 400; + src: url("./assets/fonts/nunito-v26-latin-regular.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 400; + src: url("./assets/fonts/nunito-v26-latin-italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-500 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 500; + src: url("./assets/fonts/nunito-v26-latin-500.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-500italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 500; + src: url("./assets/fonts/nunito-v26-latin-500italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-600 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 600; + src: url("./assets/fonts/nunito-v26-latin-600.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-600italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 600; + src: url("./assets/fonts/nunito-v26-latin-600italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-700 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 700; + src: url("./assets/fonts/nunito-v26-latin-700.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-700italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 700; + src: url("./assets/fonts/nunito-v26-latin-700italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-800 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 800; + src: url("./assets/fonts/nunito-v26-latin-800.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-800italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 800; + src: url("./assets/fonts/nunito-v26-latin-800italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-900 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: normal; + font-weight: 900; + src: url("./assets/fonts/nunito-v26-latin-900.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-900italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito"; + font-style: italic; + font-weight: 900; + src: url("./assets/fonts/nunito-v26-latin-900italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} + +/* nunito-sans-200 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 200; + src: url("./assets/fonts/nunito-sans-v15-latin-200.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-200italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 200; + src: url("./assets/fonts/nunito-sans-v15-latin-200italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-300 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 300; + src: url("./assets/fonts/nunito-sans-v15-latin-300.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-300italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 300; + src: url("./assets/fonts/nunito-sans-v15-latin-300italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-regular - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 400; + src: url("./assets/fonts/nunito-sans-v15-latin-regular.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 400; + src: url("./assets/fonts/nunito-sans-v15-latin-italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-500 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 500; + src: url("./assets/fonts/nunito-sans-v15-latin-500.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-500italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 500; + src: url("./assets/fonts/nunito-sans-v15-latin-500italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-600 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 600; + src: url("./assets/fonts/nunito-sans-v15-latin-600.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-600italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 600; + src: url("./assets/fonts/nunito-sans-v15-latin-600italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-700 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 700; + src: url("./assets/fonts/nunito-sans-v15-latin-700.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-700italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 700; + src: url("./assets/fonts/nunito-sans-v15-latin-700italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-800 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 800; + src: url("./assets/fonts/nunito-sans-v15-latin-800.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-800italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 800; + src: url("./assets/fonts/nunito-sans-v15-latin-800italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-900 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: normal; + font-weight: 900; + src: url("./assets/fonts/nunito-sans-v15-latin-900.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* nunito-sans-900italic - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Nunito Sans"; + font-style: italic; + font-weight: 900; + src: url("./assets/fonts/nunito-sans-v15-latin-900italic.woff2") + format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Figtree"; + font-style: normal; + font-weight: 400; + src: url("./assets/fonts/figtree-v5-latin-regular.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* figtree-500 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Figtree"; + font-style: normal; + font-weight: 500; + src: url("./assets/fonts/figtree-v5-latin-500.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* figtree-600 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Figtree"; + font-style: normal; + font-weight: 600; + src: url("./assets/fonts/figtree-v5-latin-600.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} +/* figtree-700 - latin */ +@font-face { + font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */ + font-family: "Figtree"; + font-style: normal; + font-weight: 700; + src: url("./assets/fonts/figtree-v5-latin-700.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ +} + +::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.2); + border-radius: 10px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar { + width: 6px; + height: 6px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.2); + background-color: #797ef3; +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..374cc9d --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f37b67f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,33 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "esModuleInterop": true, + "sourceMap": true, + "declaration": false, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "ES2022", + "module": "ES2022", + "useDefineForClassFields": false, + "lib": [ + "ES2022", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/tsconfig.spec.json b/tsconfig.spec.json new file mode 100644 index 0000000..be7e9da --- /dev/null +++ b/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +}