summaryrefslogtreecommitdiff
path: root/ping/frontend
diff options
context:
space:
mode:
authorMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
committerMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
commit967be9e750221ab2ab783f95df79bb26d290a45e (patch)
tree6802900a5e975f9f68b169f0f503f040056d6952 /ping/frontend
add: added projectsHEADmain
Diffstat (limited to 'ping/frontend')
-rw-r--r--ping/frontend/.dockerignore2
-rw-r--r--ping/frontend/.gitignore23
-rw-r--r--ping/frontend/.npmrc1
-rw-r--r--ping/frontend/.prettierignore6
-rw-r--r--ping/frontend/.prettierrc15
-rw-r--r--ping/frontend/Dockerfile8
-rw-r--r--ping/frontend/README.md38
-rw-r--r--ping/frontend/eslint.config.js36
-rw-r--r--ping/frontend/package-lock.json4385
-rw-r--r--ping/frontend/package.json44
-rw-r--r--ping/frontend/src/app.css58
-rw-r--r--ping/frontend/src/app.d.ts13
-rw-r--r--ping/frontend/src/app.html13
-rw-r--r--ping/frontend/src/lib/components/Avatar.svelte48
-rw-r--r--ping/frontend/src/lib/components/Button.svelte17
-rw-r--r--ping/frontend/src/lib/components/NavBar.svelte44
-rw-r--r--ping/frontend/src/lib/components/NumberStatList.svelte55
-rw-r--r--ping/frontend/src/lib/components/SideBar.svelte61
-rw-r--r--ping/frontend/src/lib/components/SteppedLineChart.svelte76
-rw-r--r--ping/frontend/src/lib/components/ToastList.svelte67
-rw-r--r--ping/frontend/src/lib/components/UserItem.svelte42
-rw-r--r--ping/frontend/src/lib/components/dashboard/RiskAnalysis.svelte10
-rw-r--r--ping/frontend/src/lib/components/dashboard/StockGraph.svelte136
-rw-r--r--ping/frontend/src/lib/components/dashboard/TrendingSymbols.svelte85
-rw-r--r--ping/frontend/src/lib/components/dashboard/transactions/TransactionModal.svelte165
-rw-r--r--ping/frontend/src/lib/components/input/StockSelector.svelte231
-rw-r--r--ping/frontend/src/lib/components/input/UserSelector.svelte35
-rw-r--r--ping/frontend/src/lib/pages.ts54
-rw-r--r--ping/frontend/src/lib/stores/auth.ts66
-rw-r--r--ping/frontend/src/lib/stores/toast.ts22
-rw-r--r--ping/frontend/src/routes/+layout.svelte9
-rw-r--r--ping/frontend/src/routes/+page.svelte59
-rw-r--r--ping/frontend/src/routes/dashboard/+layout.svelte44
-rw-r--r--ping/frontend/src/routes/dashboard/+page.svelte81
-rw-r--r--ping/frontend/src/routes/dashboard/analyses/+page.svelte409
-rw-r--r--ping/frontend/src/routes/dashboard/messages/+page.svelte403
-rw-r--r--ping/frontend/src/routes/dashboard/models/+page.svelte568
-rw-r--r--ping/frontend/src/routes/dashboard/personnel/+page.svelte290
-rw-r--r--ping/frontend/src/routes/dashboard/settings/+page.svelte452
-rw-r--r--ping/frontend/src/routes/dashboard/transactions/+page.svelte360
-rw-r--r--ping/frontend/src/routes/login/+page.svelte149
-rw-r--r--ping/frontend/src/routes/stocksapi/chart/+server.ts21
-rw-r--r--ping/frontend/src/routes/stocksapi/insights/+server.ts19
-rw-r--r--ping/frontend/src/routes/stocksapi/quote/+server.ts18
-rw-r--r--ping/frontend/src/routes/stocksapi/search/+server.ts18
-rw-r--r--ping/frontend/src/routes/stocksapi/trendingSymbols/+server.ts16
-rw-r--r--ping/frontend/static/favicon.pngbin0 -> 2329 bytes
-rw-r--r--ping/frontend/static/icons/ICI2
-rw-r--r--ping/frontend/static/icons/add-green.svg7
-rw-r--r--ping/frontend/static/icons/bell.svg25
-rw-r--r--ping/frontend/static/icons/closed-wallet.svg17
-rw-r--r--ping/frontend/static/icons/coin.svg11
-rw-r--r--ping/frontend/static/icons/credit-card.svg4
-rw-r--r--ping/frontend/static/icons/dashboard.svg5
-rw-r--r--ping/frontend/static/icons/debug.svg7
-rw-r--r--ping/frontend/static/icons/edit-pen.svg5
-rw-r--r--ping/frontend/static/icons/floppy-disk.svg18
-rw-r--r--ping/frontend/static/icons/leaf.svg19
-rw-r--r--ping/frontend/static/icons/magnifying_glass_icon.svg5
-rw-r--r--ping/frontend/static/icons/money-bills.svg27
-rw-r--r--ping/frontend/static/icons/msg.svg7
-rw-r--r--ping/frontend/static/icons/people.svg7
-rw-r--r--ping/frontend/static/icons/settings.svg30
-rw-r--r--ping/frontend/static/icons/side-menu.svg6
-rw-r--r--ping/frontend/static/icons/trash.svg35
-rw-r--r--ping/frontend/static/icons/triangle-down.svg12
-rw-r--r--ping/frontend/static/icons/triangle-up.svg11
-rw-r--r--ping/frontend/static/icons/wallet.svg15
-rw-r--r--ping/frontend/static/img/default-avatar.pngbin0 -> 6483 bytes
-rw-r--r--ping/frontend/static/img/favicon.svg29
-rw-r--r--ping/frontend/static/img/header-bg.jpgbin0 -> 53678 bytes
-rw-r--r--ping/frontend/static/img/logo.svg41
-rw-r--r--ping/frontend/static/img/logoFull.svg75
-rw-r--r--ping/frontend/svelte.config.js18
-rw-r--r--ping/frontend/tsconfig.json19
-rw-r--r--ping/frontend/vite.config.ts30
76 files changed, 9259 insertions, 0 deletions
diff --git a/ping/frontend/.dockerignore b/ping/frontend/.dockerignore
new file mode 100644
index 0000000..bcf8731
--- /dev/null
+++ b/ping/frontend/.dockerignore
@@ -0,0 +1,2 @@
+.svelte-kit
+node_modules \ No newline at end of file
diff --git a/ping/frontend/.gitignore b/ping/frontend/.gitignore
new file mode 100644
index 0000000..3b462cb
--- /dev/null
+++ b/ping/frontend/.gitignore
@@ -0,0 +1,23 @@
+node_modules
+
+# Output
+.output
+.vercel
+.netlify
+.wrangler
+/.svelte-kit
+/build
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
diff --git a/ping/frontend/.npmrc b/ping/frontend/.npmrc
new file mode 100644
index 0000000..b6f27f1
--- /dev/null
+++ b/ping/frontend/.npmrc
@@ -0,0 +1 @@
+engine-strict=true
diff --git a/ping/frontend/.prettierignore b/ping/frontend/.prettierignore
new file mode 100644
index 0000000..6562bcb
--- /dev/null
+++ b/ping/frontend/.prettierignore
@@ -0,0 +1,6 @@
+# Package Managers
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
+bun.lock
+bun.lockb
diff --git a/ping/frontend/.prettierrc b/ping/frontend/.prettierrc
new file mode 100644
index 0000000..7ebb855
--- /dev/null
+++ b/ping/frontend/.prettierrc
@@ -0,0 +1,15 @@
+{
+ "useTabs": true,
+ "singleQuote": true,
+ "trailingComma": "none",
+ "printWidth": 100,
+ "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
+ "overrides": [
+ {
+ "files": "*.svelte",
+ "options": {
+ "parser": "svelte"
+ }
+ }
+ ]
+}
diff --git a/ping/frontend/Dockerfile b/ping/frontend/Dockerfile
new file mode 100644
index 0000000..52b38c4
--- /dev/null
+++ b/ping/frontend/Dockerfile
@@ -0,0 +1,8 @@
+FROM node:24-alpine
+WORKDIR /tmp/ping/frontend
+
+COPY package*.json ./
+RUN npm install
+
+COPY . .
+ENTRYPOINT npm run dev -- --host 0.0.0.0 --port 3000 \ No newline at end of file
diff --git a/ping/frontend/README.md b/ping/frontend/README.md
new file mode 100644
index 0000000..b5b2950
--- /dev/null
+++ b/ping/frontend/README.md
@@ -0,0 +1,38 @@
+# sv
+
+Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
+
+## Creating a project
+
+If you're seeing this, you've probably already done this step. Congrats!
+
+```bash
+# create a new project in the current directory
+npx sv create
+
+# create a new project in my-app
+npx sv create my-app
+```
+
+## Developing
+
+Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
+
+```bash
+npm run dev
+
+# or start the server and open the app in a new browser tab
+npm run dev -- --open
+```
+
+## Building
+
+To create a production version of your app:
+
+```bash
+npm run build
+```
+
+You can preview the production build with `npm run preview`.
+
+> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
diff --git a/ping/frontend/eslint.config.js b/ping/frontend/eslint.config.js
new file mode 100644
index 0000000..be96133
--- /dev/null
+++ b/ping/frontend/eslint.config.js
@@ -0,0 +1,36 @@
+import prettier from 'eslint-config-prettier';
+import { includeIgnoreFile } from '@eslint/compat';
+import js from '@eslint/js';
+import svelte from 'eslint-plugin-svelte';
+import globals from 'globals';
+import { fileURLToPath } from 'node:url';
+import ts from 'typescript-eslint';
+import svelteConfig from './svelte.config.js';
+
+const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
+
+export default ts.config(
+ includeIgnoreFile(gitignorePath),
+ js.configs.recommended,
+ ...ts.configs.recommended,
+ ...svelte.configs.recommended,
+ prettier,
+ ...svelte.configs.prettier,
+ {
+ languageOptions: {
+ globals: { ...globals.browser, ...globals.node }
+ },
+ rules: { 'no-undef': 'off' }
+ },
+ {
+ files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ extraFileExtensions: ['.svelte'],
+ parser: ts.parser,
+ svelteConfig
+ }
+ }
+ }
+);
diff --git a/ping/frontend/package-lock.json b/ping/frontend/package-lock.json
new file mode 100644
index 0000000..95da3b3
--- /dev/null
+++ b/ping/frontend/package-lock.json
@@ -0,0 +1,4385 @@
+{
+ "name": "frontend",
+ "version": "0.0.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "frontend",
+ "version": "0.0.1",
+ "dependencies": {
+ "chart.js": "^4.5.0",
+ "yahoo-finance2": "^2.13.3"
+ },
+ "devDependencies": {
+ "@eslint/compat": "^1.2.5",
+ "@eslint/js": "^9.18.0",
+ "@sveltejs/adapter-auto": "^6.0.0",
+ "@sveltejs/kit": "^2.16.0",
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "@tailwindcss/forms": "^0.5.9",
+ "@tailwindcss/typography": "^0.5.15",
+ "@tailwindcss/vite": "^4.0.0",
+ "eslint": "^9.18.0",
+ "eslint-config-prettier": "^10.0.1",
+ "eslint-plugin-svelte": "^3.0.0",
+ "globals": "^16.0.0",
+ "prettier": "^3.4.2",
+ "prettier-plugin-svelte": "^3.3.3",
+ "prettier-plugin-tailwindcss": "^0.6.11",
+ "svelte": "^5.0.0",
+ "svelte-check": "^4.0.0",
+ "tailwindcss": "^4.0.0",
+ "typescript": "^5.0.0",
+ "typescript-eslint": "^8.20.0",
+ "vite": "^6.2.6",
+ "vite-plugin-devtools-json": "^0.2.0"
+ }
+ },
+ "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,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
+ "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
+ "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
+ "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
+ "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
+ "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
+ "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
+ "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
+ "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
+ "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
+ "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
+ "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
+ "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
+ "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
+ "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
+ "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
+ "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
+ "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
+ "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
+ "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
+ "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
+ "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/compat": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.3.0.tgz",
+ "integrity": "sha512-ZBygRBqpDYiIHsN+d1WyHn3TYgzgpzLEcgJUxTATyiInQbKZz6wZb6+ljwdg8xeeOe4v03z6Uh6lELiw0/mVhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "peerDependencies": {
+ "eslint": "^9.10.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.20.1",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
+ "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.6",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz",
+ "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
+ "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
+ "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "9.29.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
+ "integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
+ "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz",
+ "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.15.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz",
+ "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.6",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+ "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+ "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+ "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+ "dev": true,
+ "license": "MIT",
+ "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,
+ "license": "MIT",
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@kurkle/color": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
+ "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "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,
+ "license": "MIT",
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@polka/url": {
+ "version": "1.0.0-next.29",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+ "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz",
+ "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz",
+ "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz",
+ "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz",
+ "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz",
+ "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz",
+ "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz",
+ "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz",
+ "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz",
+ "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz",
+ "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz",
+ "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz",
+ "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz",
+ "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz",
+ "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz",
+ "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz",
+ "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz",
+ "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz",
+ "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz",
+ "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz",
+ "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@sinclair/typebox": {
+ "version": "0.32.35",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.32.35.tgz",
+ "integrity": "sha512-Ul3YyOTU++to8cgNkttakC0dWvpERr6RYoHO2W47DLbFvrwBDJUY31B1sImH6JZSYc4Kt4PyHtoPNu+vL2r2dA==",
+ "license": "MIT"
+ },
+ "node_modules/@sveltejs/acorn-typescript": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
+ "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^8.9.0"
+ }
+ },
+ "node_modules/@sveltejs/adapter-auto": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-6.0.1.tgz",
+ "integrity": "sha512-mcWud3pYGPWM2Pphdj8G9Qiq24nZ8L4LB7coCUckUEy5Y7wOWGJ/enaZ4AtJTcSm5dNK1rIkBRoqt+ae4zlxcQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@sveltejs/kit": "^2.0.0"
+ }
+ },
+ "node_modules/@sveltejs/kit": {
+ "version": "2.22.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.22.0.tgz",
+ "integrity": "sha512-DJm0UxVgzXq+1MUfiJK4Ridk7oIQsIets6JwHiEl97sI6nXScfXe+BeqNhzB7jQIVBb3BM51U4hNk8qQxRXBAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sveltejs/acorn-typescript": "^1.0.5",
+ "@types/cookie": "^0.6.0",
+ "acorn": "^8.14.1",
+ "cookie": "^0.6.0",
+ "devalue": "^5.1.0",
+ "esm-env": "^1.2.2",
+ "kleur": "^4.1.5",
+ "magic-string": "^0.30.5",
+ "mrmime": "^2.0.0",
+ "sade": "^1.8.1",
+ "set-cookie-parser": "^2.6.0",
+ "sirv": "^3.0.0",
+ "vitefu": "^1.0.6"
+ },
+ "bin": {
+ "svelte-kit": "svelte-kit.js"
+ },
+ "engines": {
+ "node": ">=18.13"
+ },
+ "peerDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0",
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
+ "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.0.tgz",
+ "integrity": "sha512-wojIS/7GYnJDYIg1higWj2ROA6sSRWvcR1PO/bqEyFr/5UZah26c8Cz4u0NaqjPeVltzsVpt2Tm8d2io0V+4Tw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
+ "debug": "^4.4.1",
+ "deepmerge": "^4.3.1",
+ "kleur": "^4.1.5",
+ "magic-string": "^0.30.17",
+ "vitefu": "^1.0.6"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22"
+ },
+ "peerDependencies": {
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz",
+ "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.7"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22"
+ },
+ "peerDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/forms": {
+ "version": "0.5.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
+ "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mini-svg-data-uri": "^1.2.3"
+ },
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1"
+ }
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.10.tgz",
+ "integrity": "sha512-2ACf1znY5fpRBwRhMgj9ZXvb2XZW8qs+oTfotJ2C5xR0/WNL7UHZ7zXl6s+rUqedL1mNi+0O+WQr5awGowS3PQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ampproject/remapping": "^2.3.0",
+ "enhanced-resolve": "^5.18.1",
+ "jiti": "^2.4.2",
+ "lightningcss": "1.30.1",
+ "magic-string": "^0.30.17",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.1.10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.10.tgz",
+ "integrity": "sha512-v0C43s7Pjw+B9w21htrQwuFObSkio2aV/qPx/mhrRldbqxbWJK6KizM+q7BF1/1CmuLqZqX3CeYF7s7P9fbA8Q==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.4",
+ "tar": "^7.4.3"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.1.10",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.10",
+ "@tailwindcss/oxide-darwin-x64": "4.1.10",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.10",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.10",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.10",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.10",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.10",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.10",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.10",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.10",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.10.tgz",
+ "integrity": "sha512-VGLazCoRQ7rtsCzThaI1UyDu/XRYVyH4/EWiaSX6tFglE+xZB5cvtC5Omt0OQ+FfiIVP98su16jDVHDEIuH4iQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.10.tgz",
+ "integrity": "sha512-ZIFqvR1irX2yNjWJzKCqTCcHZbgkSkSkZKbRM3BPzhDL/18idA8uWCoopYA2CSDdSGFlDAxYdU2yBHwAwx8euQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.10.tgz",
+ "integrity": "sha512-eCA4zbIhWUFDXoamNztmS0MjXHSEJYlvATzWnRiTqJkcUteSjO94PoRHJy1Xbwp9bptjeIxxBHh+zBWFhttbrQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.10.tgz",
+ "integrity": "sha512-8/392Xu12R0cc93DpiJvNpJ4wYVSiciUlkiOHOSOQNH3adq9Gi/dtySK7dVQjXIOzlpSHjeCL89RUUI8/GTI6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.10.tgz",
+ "integrity": "sha512-t9rhmLT6EqeuPT+MXhWhlRYIMSfh5LZ6kBrC4FS6/+M1yXwfCtp24UumgCWOAJVyjQwG+lYva6wWZxrfvB+NhQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.10.tgz",
+ "integrity": "sha512-3oWrlNlxLRxXejQ8zImzrVLuZ/9Z2SeKoLhtCu0hpo38hTO2iL86eFOu4sVR8cZc6n3z7eRXXqtHJECa6mFOvA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.10.tgz",
+ "integrity": "sha512-saScU0cmWvg/Ez4gUmQWr9pvY9Kssxt+Xenfx1LG7LmqjcrvBnw4r9VjkFcqmbBb7GCBwYNcZi9X3/oMda9sqQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.10.tgz",
+ "integrity": "sha512-/G3ao/ybV9YEEgAXeEg28dyH6gs1QG8tvdN9c2MNZdUXYBaIY/Gx0N6RlJzfLy/7Nkdok4kaxKPHKJUlAaoTdA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.10.tgz",
+ "integrity": "sha512-LNr7X8fTiKGRtQGOerSayc2pWJp/9ptRYAa4G+U+cjw9kJZvkopav1AQc5HHD+U364f71tZv6XamaHKgrIoVzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.10.tgz",
+ "integrity": "sha512-d6ekQpopFQJAcIK2i7ZzWOYGZ+A6NzzvQ3ozBvWFdeyqfOZdYHU66g5yr+/HC4ipP1ZgWsqa80+ISNILk+ae/Q==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@emnapi/wasi-threads": "^1.0.2",
+ "@napi-rs/wasm-runtime": "^0.2.10",
+ "@tybys/wasm-util": "^0.9.0",
+ "tslib": "^2.8.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.10.tgz",
+ "integrity": "sha512-i1Iwg9gRbwNVOCYmnigWCCgow8nDWSFmeTUU5nbNx3rqbe4p0kRbEqLwLJbYZKmSSp23g4N6rCDmm7OuPBXhDA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.10.tgz",
+ "integrity": "sha512-sGiJTjcBSfGq2DVRtaSljq5ZgZS2SDHSIfhOylkBvHVjwOsodBhnb3HdmiKkVuUGKD0I7G63abMOVaskj1KpOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/typography": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
+ "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash.castarray": "^4.4.0",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.merge": "^4.6.2",
+ "postcss-selector-parser": "6.0.10"
+ },
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.10.tgz",
+ "integrity": "sha512-QWnD5HDY2IADv+vYR82lOhqOlS1jSCUUAmfem52cXAhRTKxpDh3ARX8TTXJTCCO7Rv7cD2Nlekabv02bwP3a2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.1.10",
+ "@tailwindcss/oxide": "4.1.10",
+ "tailwindcss": "4.1.10"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6"
+ }
+ },
+ "node_modules/@types/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "24.0.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.4.tgz",
+ "integrity": "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "undici-types": "~7.8.0"
+ }
+ },
+ "node_modules/@types/tough-cookie": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
+ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
+ "license": "MIT"
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.0.tgz",
+ "integrity": "sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "8.35.0",
+ "@typescript-eslint/type-utils": "8.35.0",
+ "@typescript-eslint/utils": "8.35.0",
+ "@typescript-eslint/visitor-keys": "8.35.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^7.0.0",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.35.0",
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+ "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.0.tgz",
+ "integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.35.0",
+ "@typescript-eslint/types": "8.35.0",
+ "@typescript-eslint/typescript-estree": "8.35.0",
+ "@typescript-eslint/visitor-keys": "8.35.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.0.tgz",
+ "integrity": "sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.35.0",
+ "@typescript-eslint/types": "^8.35.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz",
+ "integrity": "sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.35.0",
+ "@typescript-eslint/visitor-keys": "8.35.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz",
+ "integrity": "sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.0.tgz",
+ "integrity": "sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "8.35.0",
+ "@typescript-eslint/utils": "8.35.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz",
+ "integrity": "sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.0.tgz",
+ "integrity": "sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.35.0",
+ "@typescript-eslint/tsconfig-utils": "8.35.0",
+ "@typescript-eslint/types": "8.35.0",
+ "@typescript-eslint/visitor-keys": "8.35.0",
+ "debug": "^4.3.4",
+ "fast-glob": "^3.3.2",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.0.tgz",
+ "integrity": "sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.7.0",
+ "@typescript-eslint/scope-manager": "8.35.0",
+ "@typescript-eslint/types": "8.35.0",
+ "@typescript-eslint/typescript-estree": "8.35.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.0.tgz",
+ "integrity": "sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.35.0",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "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/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,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "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,
+ "license": "Python-2.0"
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "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/chart.js": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz",
+ "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=8"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
+ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/devalue": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz",
+ "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.2",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
+ "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
+ "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.5",
+ "@esbuild/android-arm": "0.25.5",
+ "@esbuild/android-arm64": "0.25.5",
+ "@esbuild/android-x64": "0.25.5",
+ "@esbuild/darwin-arm64": "0.25.5",
+ "@esbuild/darwin-x64": "0.25.5",
+ "@esbuild/freebsd-arm64": "0.25.5",
+ "@esbuild/freebsd-x64": "0.25.5",
+ "@esbuild/linux-arm": "0.25.5",
+ "@esbuild/linux-arm64": "0.25.5",
+ "@esbuild/linux-ia32": "0.25.5",
+ "@esbuild/linux-loong64": "0.25.5",
+ "@esbuild/linux-mips64el": "0.25.5",
+ "@esbuild/linux-ppc64": "0.25.5",
+ "@esbuild/linux-riscv64": "0.25.5",
+ "@esbuild/linux-s390x": "0.25.5",
+ "@esbuild/linux-x64": "0.25.5",
+ "@esbuild/netbsd-arm64": "0.25.5",
+ "@esbuild/netbsd-x64": "0.25.5",
+ "@esbuild/openbsd-arm64": "0.25.5",
+ "@esbuild/openbsd-x64": "0.25.5",
+ "@esbuild/sunos-x64": "0.25.5",
+ "@esbuild/win32-arm64": "0.25.5",
+ "@esbuild/win32-ia32": "0.25.5",
+ "@esbuild/win32-x64": "0.25.5"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "9.29.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
+ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.20.1",
+ "@eslint/config-helpers": "^0.2.1",
+ "@eslint/core": "^0.14.0",
+ "@eslint/eslintrc": "^3.3.1",
+ "@eslint/js": "9.29.0",
+ "@eslint/plugin-kit": "^0.3.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "@types/json-schema": "^7.0.15",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "10.1.5",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz",
+ "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-config-prettier"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-svelte": {
+ "version": "3.9.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.9.3.tgz",
+ "integrity": "sha512-PlcyK80sqAZ43IITeZkgl3zPFWJytx/Joup9iKGqIOsXM2m3pWfPbWuXPr5PN3loXFEypqTY/JyZwNqlSpSvRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.6.1",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "esutils": "^2.0.3",
+ "globals": "^16.0.0",
+ "known-css-properties": "^0.37.0",
+ "postcss": "^8.4.49",
+ "postcss-load-config": "^3.1.4",
+ "postcss-safe-parser": "^7.0.0",
+ "semver": "^7.6.3",
+ "svelte-eslint-parser": "^1.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ota-meshi"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.1 || ^9.0.0",
+ "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "svelte": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esm-env": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
+ "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/espree": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrap": {
+ "version": "1.4.9",
+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.9.tgz",
+ "integrity": "sha512-3OMlcd0a03UGuZpPeUC1HxR3nA23l+HEyCiZw3b3FumJIN9KphoGzDJKMXI1S72jVS1dsenDyQC0kJlO1U9E1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ }
+ },
+ "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,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "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,
+ "license": "BSD-2-Clause",
+ "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,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "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.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/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==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.4.6",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
+ "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+ "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "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,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "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,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
+ "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-reference": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
+ "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.6"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/jiti": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
+ "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/known-css-properties": {
+ "version": "0.37.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz",
+ "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
+ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.30.1",
+ "lightningcss-darwin-x64": "1.30.1",
+ "lightningcss-freebsd-x64": "1.30.1",
+ "lightningcss-linux-arm-gnueabihf": "1.30.1",
+ "lightningcss-linux-arm64-gnu": "1.30.1",
+ "lightningcss-linux-arm64-musl": "1.30.1",
+ "lightningcss-linux-x64-gnu": "1.30.1",
+ "lightningcss-linux-x64-musl": "1.30.1",
+ "lightningcss-win32-arm64-msvc": "1.30.1",
+ "lightningcss-win32-x64-msvc": "1.30.1"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
+ "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
+ "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
+ "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
+ "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
+ "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
+ "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
+ "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
+ "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
+ "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
+ "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/locate-character": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
+ "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.castarray": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
+ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.17",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/mini-svg-data-uri": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
+ "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mini-svg-data-uri": "cli.js"
+ }
+ },
+ "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,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
+ "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+ "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mrmime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+ "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "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"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
+ "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^1.10.2"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-load-config/node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/postcss-safe-parser": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+ "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.31"
+ }
+ },
+ "node_modules/postcss-scss": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz",
+ "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss-scss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.29"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.10",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
+ "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
+ "integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-plugin-svelte": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.0.tgz",
+ "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "prettier": "^3.0.0",
+ "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
+ }
+ },
+ "node_modules/prettier-plugin-tailwindcss": {
+ "version": "0.6.13",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.13.tgz",
+ "integrity": "sha512-uQ0asli1+ic8xrrSmIOaElDu0FacR4x69GynTh2oZjFY10JUt6EEumTQl5tB4fMeD6I1naKd+4rXQQ7esT2i1g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "peerDependencies": {
+ "@ianvs/prettier-plugin-sort-imports": "*",
+ "@prettier/plugin-pug": "*",
+ "@shopify/prettier-plugin-liquid": "*",
+ "@trivago/prettier-plugin-sort-imports": "*",
+ "@zackad/prettier-plugin-twig": "*",
+ "prettier": "^3.0",
+ "prettier-plugin-astro": "*",
+ "prettier-plugin-css-order": "*",
+ "prettier-plugin-import-sort": "*",
+ "prettier-plugin-jsdoc": "*",
+ "prettier-plugin-marko": "*",
+ "prettier-plugin-multiline-arrays": "*",
+ "prettier-plugin-organize-attributes": "*",
+ "prettier-plugin-organize-imports": "*",
+ "prettier-plugin-sort-imports": "*",
+ "prettier-plugin-style-order": "*",
+ "prettier-plugin-svelte": "*"
+ },
+ "peerDependenciesMeta": {
+ "@ianvs/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "@prettier/plugin-pug": {
+ "optional": true
+ },
+ "@shopify/prettier-plugin-liquid": {
+ "optional": true
+ },
+ "@trivago/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "@zackad/prettier-plugin-twig": {
+ "optional": true
+ },
+ "prettier-plugin-astro": {
+ "optional": true
+ },
+ "prettier-plugin-css-order": {
+ "optional": true
+ },
+ "prettier-plugin-import-sort": {
+ "optional": true
+ },
+ "prettier-plugin-jsdoc": {
+ "optional": true
+ },
+ "prettier-plugin-marko": {
+ "optional": true
+ },
+ "prettier-plugin-multiline-arrays": {
+ "optional": true
+ },
+ "prettier-plugin-organize-attributes": {
+ "optional": true
+ },
+ "prettier-plugin-organize-imports": {
+ "optional": true
+ },
+ "prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "prettier-plugin-style-order": {
+ "optional": true
+ },
+ "prettier-plugin-svelte": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/psl": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
+ "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/lupomontero"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "license": "MIT"
+ },
+ "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"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz",
+ "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.44.0",
+ "@rollup/rollup-android-arm64": "4.44.0",
+ "@rollup/rollup-darwin-arm64": "4.44.0",
+ "@rollup/rollup-darwin-x64": "4.44.0",
+ "@rollup/rollup-freebsd-arm64": "4.44.0",
+ "@rollup/rollup-freebsd-x64": "4.44.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.44.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.44.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.44.0",
+ "@rollup/rollup-linux-arm64-musl": "4.44.0",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.44.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.44.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.44.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.44.0",
+ "@rollup/rollup-linux-x64-gnu": "4.44.0",
+ "@rollup/rollup-linux-x64-musl": "4.44.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.44.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.44.0",
+ "@rollup/rollup-win32-x64-msvc": "4.44.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "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"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/sade": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
+ "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mri": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sirv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz",
+ "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/svelte": {
+ "version": "5.34.8",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.34.8.tgz",
+ "integrity": "sha512-TF+8irl7rpj3+fpaLuPRX5BqReTAqckp0Fumxa/mCeK3fo0/MnBb9W/Z2bLwtqj3C3r5Lm6NKIAw7YrgIv1Fwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ampproject/remapping": "^2.3.0",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@sveltejs/acorn-typescript": "^1.0.5",
+ "@types/estree": "^1.0.5",
+ "acorn": "^8.12.1",
+ "aria-query": "^5.3.1",
+ "axobject-query": "^4.1.0",
+ "clsx": "^2.1.1",
+ "esm-env": "^1.2.1",
+ "esrap": "^1.4.8",
+ "is-reference": "^3.0.3",
+ "locate-character": "^3.0.0",
+ "magic-string": "^0.30.11",
+ "zimmerframe": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/svelte-check": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.2.2.tgz",
+ "integrity": "sha512-1+31EOYZ7NKN0YDMKusav2hhEoA51GD9Ws6o//0SphMT0ve9mBTsTUEX7OmDMadUP3KjNHsSKtJrqdSaD8CrGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "chokidar": "^4.0.1",
+ "fdir": "^6.2.0",
+ "picocolors": "^1.0.0",
+ "sade": "^1.7.4"
+ },
+ "bin": {
+ "svelte-check": "bin/svelte-check"
+ },
+ "engines": {
+ "node": ">= 18.0.0"
+ },
+ "peerDependencies": {
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
+ "typescript": ">=5.0.0"
+ }
+ },
+ "node_modules/svelte-eslint-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.2.0.tgz",
+ "integrity": "sha512-mbPtajIeuiyU80BEyGvwAktBeTX7KCr5/0l+uRGLq1dafwRNrjfM5kHGJScEBlPG3ipu6dJqfW/k0/fujvIEVw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-scope": "^8.2.0",
+ "eslint-visitor-keys": "^4.0.0",
+ "espree": "^10.0.0",
+ "postcss": "^8.4.49",
+ "postcss-scss": "^4.0.9",
+ "postcss-selector-parser": "^7.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ota-meshi"
+ },
+ "peerDependencies": {
+ "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "svelte": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/svelte-eslint-parser/node_modules/postcss-selector-parser": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+ "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.1.10",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.10.tgz",
+ "integrity": "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
+ "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
+ "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.0.1",
+ "mkdirp": "^3.0.1",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
+ "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/totalist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
+ "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.2.0",
+ "url-parse": "^1.5.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tough-cookie-file-store": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie-file-store/-/tough-cookie-file-store-2.0.3.tgz",
+ "integrity": "sha512-sMpZVcmFf6EYFHFFl+SYH4W1/OnXBYMGDsv2IlbQ2caHyFElW/UR/gpj/KYU1JwmP4dE9xqwv2+vWcmlXHojSw==",
+ "license": "MIT",
+ "dependencies": {
+ "tough-cookie": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
+ "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.35.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.0.tgz",
+ "integrity": "sha512-uEnz70b7kBz6eg/j0Czy6K5NivaYopgxRjsnAJ2Fx5oTLo3wefTHIbL7AkQr1+7tJCRVpTs/wiM8JR/11Loq9A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.35.0",
+ "@typescript-eslint/parser": "8.35.0",
+ "@typescript-eslint/utils": "8.35.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
+ "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true
+ },
+ "node_modules/universalify": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.0.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==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uuid": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
+ "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/esm/bin/uuid"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.3.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
+ "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.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 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-devtools-json": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-devtools-json/-/vite-plugin-devtools-json-0.2.0.tgz",
+ "integrity": "sha512-K7PoaWOEJECZ1n3VbhJXsUAX2PsO0xY7KFMM/Leh7tUev0M5zi+lz+vnVVdCK17IOK9Jp9rdzHXc08cnQirGbg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "uuid": "^11.1.0"
+ },
+ "peerDependencies": {
+ "vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
+ }
+ },
+ "node_modules/vitefu": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.7.tgz",
+ "integrity": "sha512-eRWXLBbJjW3X5z5P5IHcSm2yYbYRPb2kQuc+oqsbAl99WB5kVsPbiiox+cymo8twTzifA6itvhr2CmjnaZZp0Q==",
+ "dev": true,
+ "license": "MIT",
+ "workspaces": [
+ "tests/deps/*",
+ "tests/projects/*"
+ ],
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "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,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/yahoo-finance2": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/yahoo-finance2/-/yahoo-finance2-2.13.3.tgz",
+ "integrity": "sha512-ZECy6wQ7ymT08nVrxqQf+gwmINJ4/ECLyq+vM3SQmH3HWzje5DX1WX5YcZpWpWi4KXdmo2Vuk9OAdrTP09nE4g==",
+ "license": "MIT",
+ "dependencies": {
+ "@sinclair/typebox": "^0.32.27",
+ "@types/tough-cookie": "^4.0.2",
+ "tough-cookie": "^4.1.2",
+ "tough-cookie-file-store": "^2.0.3"
+ },
+ "bin": {
+ "yahoo-finance": "bin/yahoo-finance.js"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/yaml": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
+ "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "peer": true,
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zimmerframe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
+ "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
+ "dev": true,
+ "license": "MIT"
+ }
+ }
+}
diff --git a/ping/frontend/package.json b/ping/frontend/package.json
new file mode 100644
index 0000000..ac61dfe
--- /dev/null
+++ b/ping/frontend/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "frontend",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "prepare": "svelte-kit sync || echo ''",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+ "format": "prettier --write .",
+ "lint": "prettier --check . && eslint ."
+ },
+ "devDependencies": {
+ "@eslint/compat": "^1.2.5",
+ "@eslint/js": "^9.18.0",
+ "@sveltejs/adapter-auto": "^6.0.0",
+ "@sveltejs/kit": "^2.16.0",
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "@tailwindcss/forms": "^0.5.9",
+ "@tailwindcss/typography": "^0.5.15",
+ "@tailwindcss/vite": "^4.0.0",
+ "eslint": "^9.18.0",
+ "eslint-config-prettier": "^10.0.1",
+ "eslint-plugin-svelte": "^3.0.0",
+ "globals": "^16.0.0",
+ "prettier": "^3.4.2",
+ "prettier-plugin-svelte": "^3.3.3",
+ "prettier-plugin-tailwindcss": "^0.6.11",
+ "svelte": "^5.0.0",
+ "svelte-check": "^4.0.0",
+ "tailwindcss": "^4.0.0",
+ "typescript": "^5.0.0",
+ "typescript-eslint": "^8.20.0",
+ "vite": "^6.2.6",
+ "vite-plugin-devtools-json": "^0.2.0"
+ },
+ "dependencies": {
+ "chart.js": "^4.5.0",
+ "yahoo-finance2": "^2.13.3"
+ }
+}
diff --git a/ping/frontend/src/app.css b/ping/frontend/src/app.css
new file mode 100644
index 0000000..42e2b32
--- /dev/null
+++ b/ping/frontend/src/app.css
@@ -0,0 +1,58 @@
+@import 'tailwindcss';
+@plugin '@tailwindcss/forms';
+@plugin '@tailwindcss/typography';
+
+:root {
+ --bg-primary: #1A1C22;
+ --bg-secondary: #282C35;
+ --btn-primary: #343844;
+ --btn-primary-hover: #2d8f3a;
+ --btn-secondary: #454b5a;
+ --text-lime: #00FF77;
+}
+
+body {
+ background-color: var(--bg-secondary);
+}
+
+input,select,textarea {
+ background-color: var(--bg-secondary);
+ border:none;
+ border-bottom: 2px solid var(--text-lime);
+ padding: 8px;
+ border-radius: 8px 8px 0 0;
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+ accent-color: var(--text-lime);
+ border-radius: 8px;
+ border:none;
+}
+
+.btn {
+ background-color: var(--btn-primary);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ text-decoration: none;
+ transition-duration: 0.2s;
+ font-weight: 600;
+}
+
+.btn:hover {
+ background-color: var(--btn-primary-hover);
+ transform: scale(1.025);
+}
+
+.card {
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 16px;
+ margin: 16px;
+ color: white;
+ width: 100%;
+} \ No newline at end of file
diff --git a/ping/frontend/src/app.d.ts b/ping/frontend/src/app.d.ts
new file mode 100644
index 0000000..da08e6d
--- /dev/null
+++ b/ping/frontend/src/app.d.ts
@@ -0,0 +1,13 @@
+// See https://svelte.dev/docs/kit/types#app.d.ts
+// for information about these interfaces
+declare global {
+ namespace App {
+ // interface Error {}
+ // interface Locals {}
+ // interface PageData {}
+ // interface PageState {}
+ // interface Platform {}
+ }
+}
+
+export {};
diff --git a/ping/frontend/src/app.html b/ping/frontend/src/app.html
new file mode 100644
index 0000000..e37ecf4
--- /dev/null
+++ b/ping/frontend/src/app.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+ <link rel="icon" href="%sveltekit.assets%/favicon.png" />
+ <title>Patapimvest</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ %sveltekit.head%
+ </head>
+ <body data-sveltekit-preload-data="hover">
+ <div style="display: contents">%sveltekit.body%</div>
+ </body>
+</html>
diff --git a/ping/frontend/src/lib/components/Avatar.svelte b/ping/frontend/src/lib/components/Avatar.svelte
new file mode 100644
index 0000000..c04b563
--- /dev/null
+++ b/ping/frontend/src/lib/components/Avatar.svelte
@@ -0,0 +1,48 @@
+<script lang="ts">
+ let showTooltip = $state(false);
+
+ interface Props {
+ username?: string;
+ url?: string;
+ onclick?: () => void;
+ }
+
+ let { username = 'lolo', url = '/img/default-avatar.png', onclick = () => {} }: Props = $props();
+</script>
+
+<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
+<div style="position: relative; display: inline-block;">
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
+ <img
+ src={url ?? '/img/default-avatar.png'}
+ onmouseenter={() => (showTooltip = true)}
+ onmouseleave={() => (showTooltip = false)}
+ {onclick}
+ alt="User Avatar"
+ />
+ {#if showTooltip}
+ <div class="tooltip">{username}</div>
+ {/if}
+</div>
+
+<style>
+ img {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ }
+ .tooltip {
+ position: absolute;
+ top: 110%;
+ left: 50%;
+ transform: translateX(-50%);
+ background: #333;
+ color: #fff;
+ padding: 4px 8px;
+ border-radius: 4px;
+ white-space: nowrap;
+ font-size: 0.9em;
+ z-index: 1;
+ pointer-events: none;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/Button.svelte b/ping/frontend/src/lib/components/Button.svelte
new file mode 100644
index 0000000..54b26ab
--- /dev/null
+++ b/ping/frontend/src/lib/components/Button.svelte
@@ -0,0 +1,17 @@
+<script lang="ts">
+ // Accept props and ensure onclick matches the expected event handler signature
+ const {
+ href = undefined as string | undefined,
+ onclick = undefined as
+ | ((event: MouseEvent & { currentTarget: EventTarget & HTMLButtonElement }) => void)
+ | undefined,
+ disabled = false,
+ children
+ } = $props();
+</script>
+
+{#if href}
+ <a class="btn" {href}>{@render children?.()}</a>
+{:else}
+ <button class="btn" {onclick} {disabled}>{@render children?.()}</button>
+{/if}
diff --git a/ping/frontend/src/lib/components/NavBar.svelte b/ping/frontend/src/lib/components/NavBar.svelte
new file mode 100644
index 0000000..1a76876
--- /dev/null
+++ b/ping/frontend/src/lib/components/NavBar.svelte
@@ -0,0 +1,44 @@
+<script lang="ts">
+ const { pageTitle, rightComponent } = $props();
+</script>
+
+<nav>
+ <a id="logo" href="/">
+ <img src="/img/logo.svg" alt="" style="height:50px" />
+ </a>
+ <div id="middletitle">{pageTitle}</div>
+ <div id="right">{@render rightComponent()}</div>
+</nav>
+
+<style>
+ nav {
+ position: fixed;
+ width: 100%;
+ background-color: var(--bg-primary);
+ color: white;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px;
+ height: 64px;
+ z-index: 2;
+ }
+
+ #logo {
+ transition-duration: 0.2s;
+ }
+
+ #logo:hover {
+ transform: scale(1.025);
+ filter: saturate(2);
+ }
+
+ #middletitle {
+ font-weight: bold;
+ font-size: 24px;
+ }
+
+ #right {
+ display: flex;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/NumberStatList.svelte b/ping/frontend/src/lib/components/NumberStatList.svelte
new file mode 100644
index 0000000..b6444e8
--- /dev/null
+++ b/ping/frontend/src/lib/components/NumberStatList.svelte
@@ -0,0 +1,55 @@
+<script lang="ts">
+ export interface INumberStatList {
+ name: string;
+ value: string;
+ icon: string;
+ color: string;
+ }
+
+ const { statsList = [] }: { statsList?: INumberStatList[] } = $props();
+</script>
+
+<section class="numberStatList">
+ {#each statsList as stat}
+ <div class="card">
+ <img src={stat.icon} alt="" class="stat-icon" />
+ <span class="stat-name">{stat.name}</span>
+ <span class="stat-value" style:color={stat.color}>{stat.value}</span>
+ </div>
+ {/each}
+</section>
+
+<style>
+ .numberStatList {
+ color: white;
+ display: flex;
+ width: 100%;
+ align-items: stretch;
+ justify-content: stretch;
+ }
+
+ .numberStatList :global(.card) {
+ flex: 1;
+ display: grid;
+ grid-template-areas: 'icon name' 'icon amount';
+ align-items: center;
+ justify-content: space-around;
+ }
+
+ .stat-icon {
+ width: 24px;
+ height: 24px;
+ grid-area: icon;
+ }
+
+ .stat-name {
+ grid-area: name;
+ font-weight: bold;
+ }
+
+ .stat-value {
+ grid-area: amount;
+ font-size: 1.2em;
+ font-weight: bold;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/SideBar.svelte b/ping/frontend/src/lib/components/SideBar.svelte
new file mode 100644
index 0000000..9ea8a04
--- /dev/null
+++ b/ping/frontend/src/lib/components/SideBar.svelte
@@ -0,0 +1,61 @@
+<script lang="ts">
+ import { pages } from '$lib/pages';
+
+ const {
+ selectedIndex = $bindable(0)
+ }: {
+ selectedIndex: number;
+ } = $props();
+
+ const items = pages;
+</script>
+
+<section id="sidebar">
+ {#each items as item, index}
+ <!-- svelte-ignore a11y_consider_explicit_label -->
+ <a href={item.href} class:selected={index == selectedIndex} class="flex items-center gap-2">
+ <img
+ src={item.icon}
+ alt=" "
+ class="w-6"
+ style="filter: {index == selectedIndex
+ ? 'invert(68%) sepia(97%) saturate(749%) hue-rotate(97deg) brightness(154%) contrast(101%)'
+ : 'none'};"
+ />
+ <span>{item.name}</span>
+ </a>
+ {/each}
+</section>
+
+<style>
+ #sidebar {
+ position: fixed;
+ background-color: var(--bg-primary);
+ height: 100vh;
+ width: 200px;
+ padding-top: 72px;
+ color: white;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ #sidebar > a {
+ padding: 8px;
+ padding-right: 0;
+ transition-duration: 0.2s;
+ border-color: var(--text-lime);
+ }
+
+ #sidebar > a:is(:hover, :focus) {
+ background-color: var(--bg-secondary);
+ }
+
+ .selected {
+ color: var(--text-lime);
+ background-color: var(--bg-secondary);
+ font-weight: bold;
+ border-right: 6px var(--text-lime) solid;
+ width: 100%;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/SteppedLineChart.svelte b/ping/frontend/src/lib/components/SteppedLineChart.svelte
new file mode 100644
index 0000000..d393b44
--- /dev/null
+++ b/ping/frontend/src/lib/components/SteppedLineChart.svelte
@@ -0,0 +1,76 @@
+<script lang="ts">
+ import {
+ Chart,
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend,
+ LineController
+ } from 'chart.js';
+ import { onMount } from 'svelte';
+
+ Chart.register(
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend,
+ LineController
+ );
+
+ interface IProps {
+ color?: string;
+ data?: any[];
+ title?: string;
+ legend?: string;
+ }
+
+ const { color = 'green', data = [], title = '', legend = '' }: IProps = $props();
+
+ function updateGraph() {
+ const ctx = document.getElementById(id) as HTMLCanvasElement;
+ const chart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ labels: data.map((d) => d.label),
+ datasets: [
+ {
+ label: legend,
+ data: data.map((d) => d.value),
+ borderColor: color,
+ backgroundColor: color,
+ fill: false,
+ tension: 0.1
+ }
+ ]
+ },
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: title
+ },
+ legend: {
+ display: true
+ }
+ }
+ }
+ });
+ }
+
+ const id = 'graph-' + crypto.randomUUID();
+
+ onMount(() => {
+ updateGraph();
+ });
+</script>
+
+<div>
+ <canvas {id}></canvas>
+</div>
diff --git a/ping/frontend/src/lib/components/ToastList.svelte b/ping/frontend/src/lib/components/ToastList.svelte
new file mode 100644
index 0000000..5351ef7
--- /dev/null
+++ b/ping/frontend/src/lib/components/ToastList.svelte
@@ -0,0 +1,67 @@
+<script lang="ts">
+ import { toastList } from '$lib/stores/toast';
+</script>
+
+<div class="toast">
+ {#each $toastList as toast}
+ <div class="toast-item" style="border-top: 4px {toast.color} solid">
+ <h3 style="color: {toast.color}">{toast.title}</h3>
+ <p>{toast.message}</p>
+ </div>
+ {/each}
+</div>
+
+<style>
+ .toast {
+ position: fixed;
+ bottom: 20px;
+ right: 20px;
+ z-index: 1000;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+
+ .toast-item {
+ background-color: var(--bg-secondary);
+ padding: 10px;
+ color: white;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ transition:
+ transform 0.3s,
+ opacity 0.3s;
+ transform: translateY(30px);
+ opacity: 0;
+ animation-delay: 0s, 4.7s;
+ animation-name: toast-in, toast-out;
+ animation-duration: 0.3s, 0.3s;
+ animation-fill-mode: forwards, forwards;
+ }
+
+ @keyframes toast-in {
+ from {
+ transform: translateY(30px);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0);
+ opacity: 1;
+ }
+ }
+
+ @keyframes toast-out {
+ from {
+ transform: translateY(0);
+ opacity: 1;
+ }
+ to {
+ transform: translateY(30px);
+ opacity: 0;
+ }
+ }
+
+ .toast-item h3 {
+ margin: 0;
+ font-weight: bold;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/UserItem.svelte b/ping/frontend/src/lib/components/UserItem.svelte
new file mode 100644
index 0000000..44add60
--- /dev/null
+++ b/ping/frontend/src/lib/components/UserItem.svelte
@@ -0,0 +1,42 @@
+<script lang="ts">
+ import Avatar from './Avatar.svelte';
+ import type { IUser } from '$lib/stores/auth';
+
+ const { user, onEdit, onDelete }: { user: IUser; onEdit: any; onDelete: any } = $props();
+</script>
+
+<div class="useritem">
+ <div class="useritem-avatar">
+ <Avatar username={user.displayName} url={user.avatar || '/img/default-avatar.png'} />
+ <button class="btn" onclick={onEdit}> Modifier </button>
+ <button class="btn" onclick={onDelete}> Supprimer </button>
+ </div>
+ <div class="useritem-details">
+ <p><b>Nom</b>: {user.displayName}</p>
+ <p><b>Login</b>: {user.login}</p>
+ <p><b>Role</b>: {user.isAdmin ? 'ADMIN' : 'USER'}</p>
+ <p><b>Id</b>: {user.id}</p>
+ </div>
+</div>
+
+<style>
+ .useritem {
+ display: flex;
+ background-color: var(--bg-secondary);
+ margin: 16px 0;
+ padding: 8px;
+ border-radius: 8px;
+ gap: 8px;
+ }
+
+ .useritem-avatar,
+ .useritem-details {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ .useritem-avatar {
+ align-items: center;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/dashboard/RiskAnalysis.svelte b/ping/frontend/src/lib/components/dashboard/RiskAnalysis.svelte
new file mode 100644
index 0000000..3844abc
--- /dev/null
+++ b/ping/frontend/src/lib/components/dashboard/RiskAnalysis.svelte
@@ -0,0 +1,10 @@
+<h2>Analyse de risque</h2>
+<i>tkt t safe c hardcodé chef</i>
+
+<style>
+ h2 {
+ font-weight: bold;
+ color: var(--text-lime);
+ font-size: 24px;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/dashboard/StockGraph.svelte b/ping/frontend/src/lib/components/dashboard/StockGraph.svelte
new file mode 100644
index 0000000..beefed9
--- /dev/null
+++ b/ping/frontend/src/lib/components/dashboard/StockGraph.svelte
@@ -0,0 +1,136 @@
+<script lang="ts">
+ import Chart from 'chart.js/auto';
+ import { onMount } from 'svelte';
+ import StockSelector from '../input/StockSelector.svelte';
+
+ async function fetchChartData(stock: string, startDate: string, endDate: string) {
+ const res = await fetch(
+ `/stocksapi/chart?query=${stock}&startDate=${startDate}&endDate=${endDate}&interval=${range}`,
+ {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache'
+ }
+ }
+ );
+ return await res.json();
+ }
+
+ function updateGraph() {
+ fetchChartData(selectedStock, startDate, endDate).then((data) => {
+ if (chart) {
+ chart.destroy();
+ chart = null;
+ }
+
+ const { quotes, meta } = data;
+
+ validRanges = meta.validRanges;
+
+ const labels = quotes.map((item: any) => item.date.split('T')[0]);
+ const datasets = ['low', 'high', 'open', 'close'].map((key) => ({
+ label: key.charAt(0).toUpperCase() + key.slice(1),
+ data: quotes.map((item: any) => item[key]),
+ borderColor:
+ key === 'low'
+ ? 'rgb(255, 99, 132)'
+ : key === 'high'
+ ? 'rgb(54, 162, 235)'
+ : key === 'open'
+ ? 'rgb(255, 205, 86)'
+ : 'rgb(75, 192, 192)',
+ fill: false
+ }));
+
+ // @ts-ignore
+ chart = new Chart(document.getElementById('stockgraph'), {
+ type: 'line',
+ data: {
+ labels,
+ datasets
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: true,
+ plugins: {
+ title: {
+ display: true,
+ text: meta.longName
+ }
+ }
+ }
+ });
+ });
+ }
+
+ let today = $state(new Date().toISOString().split('T')[0]);
+
+ let selectedStock = $state('2223.SR');
+ let startDate = $state('');
+ let endDate = $state('');
+ let chart = $state<Chart | null>(null);
+ let range = $state('1d');
+ let validRanges = $state(['1d']);
+
+ onMount(() => {
+ endDate = new Date().toISOString().split('T')[0];
+ startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
+
+ updateGraph();
+ });
+
+ $effect(() => {
+ if (selectedStock && startDate && endDate && range) {
+ updateGraph();
+ }
+ });
+
+ $effect(() => {
+ if (startDate && endDate && startDate > endDate) {
+ let temp = startDate;
+ startDate = endDate;
+ endDate = temp;
+ }
+ });
+</script>
+
+<div>
+ <div class="header">
+ <h2>Vue d'ensemble : {selectedStock}</h2>
+ <div class="controls">
+ <input type="date" name="startDate" id="startDate" bind:value={startDate} max={today} />
+ <input type="date" name="endDate" id="endDate" bind:value={endDate} max={today} />
+ <select name="validRanges" id="validRanges" bind:value={range}>
+ {#each validRanges as r}
+ <option value={r}>
+ {r}
+ </option>
+ {/each}
+ </select>
+
+ <StockSelector bind:selectedStock />
+ </div>
+ </div>
+ <canvas id="stockgraph"></canvas>
+</div>
+
+<style>
+ .header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ max-height: 512px !important;
+ }
+
+ h2 {
+ font-weight: bold;
+ color: var(--text-lime);
+ font-size: 24px;
+ }
+
+ #stockgraph {
+ width: 100% !important;
+ max-height: 512px !important;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/dashboard/TrendingSymbols.svelte b/ping/frontend/src/lib/components/dashboard/TrendingSymbols.svelte
new file mode 100644
index 0000000..3d947ad
--- /dev/null
+++ b/ping/frontend/src/lib/components/dashboard/TrendingSymbols.svelte
@@ -0,0 +1,85 @@
+<script lang="ts">
+ import { Chart } from 'chart.js';
+ import { onMount } from 'svelte';
+
+ function updateGraph() {
+ getTrendingSymbols().then((trendingSymbols) => {
+ const labels = trendingSymbols.map((d) => d.longName);
+
+ const datasets = [
+ {
+ label: '50 day performance',
+ data: trendingSymbols.map((ts) => ts.fiftyDayAverageChange),
+ backgroundColor: 'green'
+ },
+ {
+ label: '52 week performance',
+ data: trendingSymbols.map((ts) => ts.fiftyTwoWeekLowChange),
+ backgroundColor: 'orange'
+ }
+ ];
+
+ const data = { labels, datasets };
+
+ // @ts-ignore
+ new Chart(document.getElementById('graph'), {
+ type: 'bar',
+ data: data,
+ options: {
+ indexAxis: 'y',
+ elements: {
+ bar: {
+ borderWidth: 2
+ }
+ },
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'bottom'
+ }
+ }
+ }
+ });
+ });
+ }
+
+ async function getTrendingSymbols() {
+ const trendingRes = await fetch('/stocksapi/trendingSymbols');
+ if (!trendingRes.ok) {
+ throw new Error('Failed to fetch trending symbols');
+ }
+ const trendingJson = await trendingRes.json();
+
+ const { quotes } = trendingJson;
+
+ const trendingSymbols = await Promise.all(
+ quotes.map(async (quote: any) => {
+ const quoteRes = await fetch(`/stocksapi/quote?query=${quote.symbol}`);
+ const quoteJson = await quoteRes.json();
+ return quoteJson;
+ })
+ );
+
+ return trendingSymbols;
+ }
+
+ onMount(() => {
+ updateGraph();
+ });
+</script>
+
+<h2>Tendances</h2>
+<canvas id="graph"></canvas>
+
+<style>
+ h2 {
+ font-weight: bold;
+ color: var(--text-lime);
+ font-size: 24px;
+ }
+
+ #graph {
+ max-height: 40vh;
+ max-width: 40vw;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/dashboard/transactions/TransactionModal.svelte b/ping/frontend/src/lib/components/dashboard/transactions/TransactionModal.svelte
new file mode 100644
index 0000000..b9f0224
--- /dev/null
+++ b/ping/frontend/src/lib/components/dashboard/transactions/TransactionModal.svelte
@@ -0,0 +1,165 @@
+<script lang="ts">
+ import { authFetch } from '$lib/stores/auth';
+ import { onMount } from 'svelte';
+
+ interface IProps {
+ isOpen: boolean;
+ onCreate: (transaction: any) => void;
+ }
+
+ let { isOpen = $bindable(false), onCreate = () => {} }: IProps = $props(); // Changed default to false
+
+ let amount: number = $state(0);
+ let currency: string = $state('USD');
+ let label: string = $state('');
+ let receiverLabel: string = $state('');
+ let receiverIban: string = $state('');
+ let operationDate: string = $state('');
+
+ function closeDialog() {
+ isOpen = false;
+ }
+
+ async function createTransaction(event: Event) {
+ event.preventDefault();
+
+ const transaction = {
+ amount,
+ currency,
+ label,
+ receiverLabel,
+ receiverIban,
+ operationDate
+ };
+
+ try {
+ const response = await authFetch('/api/transactions', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(transaction)
+ });
+
+ if (!response.ok) {
+ const error = await response.json();
+ alert('Erreur lors de la création de la transaction: ' + error);
+ return;
+ }
+
+ onCreate(await response.json());
+
+ closeDialog();
+ } catch (err) {
+ alert('Erreur réseau lors de la création de la transaction');
+ }
+ }
+</script>
+
+<!-- svelte-ignore a11y_click_events_have_key_events -->
+<!-- svelte-ignore a11y_no_static_element_interactions -->
+{#if isOpen}
+ <div class="backdrop" onclick={closeDialog}>
+ <dialog open onclick={(e) => e.stopPropagation()}>
+ <h2>Créer une nouvelle transaction</h2>
+ <form class="flex flex-col gap-2">
+ <label>
+ <span>Montant</span>
+ <input type="number" step="0.01" min="0" bind:value={amount} required />
+ </label>
+ <label>
+ <span>Devise</span>
+ <select bind:value={currency} required>
+ <option selected value="USD" data-symbol="$" data-name="Dollar américain"
+ >USD - Dollar américain</option
+ >
+ <option value="EUR" data-symbol="€" data-name="Euro">EUR - Euro</option>
+ <option value="GBP" data-symbol="£" data-name="Livre sterling"
+ >GBP - Livre sterling</option
+ >
+ <option value="JPY" data-symbol="¥" data-name="Yen japonais">JPY - Yen japonais</option>
+ <option value="CHF" data-symbol="Fr" data-name="Franc suisse">CHF - Franc suisse</option
+ >
+ <option value="CAD" data-symbol="$" data-name="Dollar canadien"
+ >CAD - Dollar canadien</option
+ >
+ <option value="AUD" data-symbol="$" data-name="Dollar australien"
+ >AUD - Dollar australien</option
+ >
+ <option value="CNY" data-symbol="¥" data-name="Yuan chinois">CNY - Yuan chinois</option>
+ </select>
+ </label>
+ <label>
+ <span>Libellé</span>
+ <input type="text" bind:value={label} required />
+ </label>
+ <label>
+ <span>Libellé du bénéficiaire</span>
+ <input type="text" bind:value={receiverLabel} required />
+ </label>
+ <label>
+ <span>IBAN du bénéficiaire</span>
+ <input type="text" bind:value={receiverIban} required />
+ </label>
+ <label>
+ <span>Date de l'opération</span>
+ <input type="datetime-local" bind:value={operationDate} required />
+ </label>
+ <button class="btn" onclick={createTransaction}>➕ Créer</button>
+ </form>
+ </dialog>
+ </div>
+{/if}
+
+<style>
+ .backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ background: rgba(0, 0, 0, 0.4);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ }
+
+ dialog {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ max-width: 90vw;
+ max-height: 90vh;
+ border: none;
+ border-radius: 8px;
+ box-shadow: 0 2px 16px rgba(0, 0, 0, 0.2);
+ padding: 2rem;
+ background: var(--bg-primary);
+ outline: none;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ align-items: center;
+ justify-content: center;
+ color: white;
+ }
+
+ h2 {
+ font-weight: 600;
+ font-size: 32px;
+ color: var(--text-lime);
+ }
+
+ form {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ label {
+ display: flex;
+ flex-direction: column;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/input/StockSelector.svelte b/ping/frontend/src/lib/components/input/StockSelector.svelte
new file mode 100644
index 0000000..1237128
--- /dev/null
+++ b/ping/frontend/src/lib/components/input/StockSelector.svelte
@@ -0,0 +1,231 @@
+<script lang="ts">
+ import { onMount } from 'svelte';
+ import Button from '../Button.svelte';
+
+ let { selectedStock = $bindable('AAPL') } = $props();
+
+ let stocks: {
+ symbol: string;
+ shortname: string;
+ quoteType: string;
+ isYahooFinance: boolean;
+ }[] = $state([]);
+ let news: {
+ link: string;
+ title: string;
+ thumbnail: { resolutions: { url: string; width: number; height: number }[] };
+ }[] = $state([]);
+
+ function openDialog() {
+ const dialog = document.querySelector('dialog');
+ const backdrop = document.getElementById('backdrop');
+ // @ts-ignore
+ dialog.open = true;
+ // @ts-ignore
+ backdrop.style.display = 'block';
+ }
+
+ function closeDialog() {
+ const dialog = document.querySelector('dialog');
+ const backdrop = document.getElementById('backdrop');
+ // @ts-ignore
+ dialog.open = false;
+ // @ts-ignore
+ backdrop.style.display = 'none';
+ }
+
+ function onSearch(event: SubmitEvent) {
+ event.preventDefault();
+ // @ts-ignore
+ const fd = new FormData(event.target);
+ const searchQuery = fd.get('search');
+
+ fetch(`/stocksapi/search?query=${searchQuery}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache'
+ }
+ })
+ .then((response) => response.json())
+ .then((data) => {
+ stocks = data.quotes.filter((q: any) => q.isYahooFinance);
+ news = data.news;
+ })
+ .catch((error) => {
+ console.error('Error fetching stock data:', error);
+ });
+ }
+
+ onMount(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === 'Escape') {
+ closeDialog();
+ }
+ };
+ window.addEventListener('keydown', handleKeyDown);
+ return () => {
+ window.removeEventListener('keydown', handleKeyDown);
+ };
+ });
+</script>
+
+<Button onclick={openDialog}>{selectedStock}</Button>
+
+<dialog>
+ <form onsubmit={onSearch}>
+ <input
+ type="search"
+ name="search"
+ id="search"
+ placeholder="Recherche d'actions, ETFs, entreprises"
+ value={selectedStock || ''}
+ />
+ <button type="submit" class="btn">Rechercher</button>
+ </form>
+ <div class="results">
+ <div class="stocks">
+ {#if stocks.length === 0}
+ <p>Aucune action, ETFs trouvés.</p>
+ {:else}
+ <p>{stocks.length} actions, ETFs trouvés</p>
+ {#each stocks as stock}
+ <button
+ class="btn stock"
+ onclick={() => {
+ selectedStock = stock.symbol;
+ closeDialog();
+ }}
+ disabled={!stock.isYahooFinance}
+ >
+ <pre>{stock.symbol}</pre>
+ <span>{stock.shortname}</span>
+ <i>{stock.quoteType}</i>
+ </button>
+ {/each}
+ {/if}
+ </div>
+ <div class="news">
+ {#if news.length === 0}
+ <p>Pas de news trouvés.</p>
+ {:else}
+ <p>{news.length} news trouvées</p>
+ {#each news as newsItem}
+ <a class="newsItem" href={newsItem.link}>
+ {#if newsItem.thumbnail?.resolutions?.length > 0}
+ <img
+ src={newsItem.thumbnail.resolutions[0].url}
+ alt="News Thumbnail"
+ width={newsItem.thumbnail.resolutions[0].width}
+ height={newsItem.thumbnail.resolutions[0].height}
+ />
+ {/if}
+ <h1>{newsItem.title}</h1></a
+ >
+ {/each}
+ {/if}
+ </div>
+ </div>
+</dialog>
+<!-- svelte-ignore a11y_click_events_have_key_events -->
+<!-- svelte-ignore a11y_no_static_element_interactions -->
+<div id="backdrop" onclick={closeDialog}></div>
+
+<style>
+ dialog {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 300px;
+ padding: 20px;
+ background-color: var(--bg-primary);
+ border: 4px solid #ccc;
+ border-radius: 16px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ height: 90vh;
+ width: 90vw;
+ z-index: 1000;
+ color: white;
+ }
+
+ #backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 999;
+ display: none;
+ }
+
+ form {
+ display: flex;
+ gap: 10px;
+ }
+
+ input[type='search'] {
+ width: 300px;
+ }
+
+ .results {
+ display: flex;
+ flex-direction: row;
+ gap: 20px;
+ justify-content: space-evenly;
+ }
+
+ .stocks,
+ .news {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ overflow-y: auto;
+ max-height: 70vh;
+ padding: 16px;
+ flex: 1;
+ }
+
+ .stock {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .stock pre {
+ font-weight: bold;
+ padding: 8px;
+ background: var(--bg-primary);
+ border-radius: 8px;
+ }
+
+ .stock span {
+ font-weight: bold;
+ color: var(--text-lime);
+ }
+
+ .newsItem {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--bg-secondary);
+ padding-bottom: 4px;
+ border-radius: 8px;
+ transition-duration: 0.2s;
+ }
+
+ .newsItem h1 {
+ margin: 16px;
+ }
+
+ .newsItem img {
+ border-radius: 8px;
+ width: 100%;
+ height: auto;
+ }
+
+ .newsItem:hover {
+ transform: scale(1.025);
+ background-color: #333;
+ }
+</style>
diff --git a/ping/frontend/src/lib/components/input/UserSelector.svelte b/ping/frontend/src/lib/components/input/UserSelector.svelte
new file mode 100644
index 0000000..a0c80c7
--- /dev/null
+++ b/ping/frontend/src/lib/components/input/UserSelector.svelte
@@ -0,0 +1,35 @@
+<script lang="ts">
+ import type { IUser } from '$lib/stores/auth';
+ import { addToast } from '$lib/stores/toast';
+ import Avatar from '../Avatar.svelte';
+
+ let { users = $bindable<IUser[]>([]) }: { users: IUser[] } = $props();
+</script>
+
+<div>
+ {#each users as u, i}
+ <Avatar
+ username={u.displayName}
+ url={u.avatar}
+ onclick={() => {
+ users = users.filter((_, index) => index !== i);
+ }}
+ />
+ {/each}
+ <Avatar
+ username={'Ajouter un utilisateur'}
+ url={'/icons/add-green.svg'}
+ onclick={() => {
+ let userId = prompt("Entrez l'ID de l'utilisateur à ajouter :");
+ if (userId === null || userId.trim() === '') {
+ addToast({ title: 'ID utilisateur invalide.' });
+ return;
+ }
+ if (users.map((u) => u.displayName).includes(userId)) {
+ addToast({ title: 'Cet utilisateur est déjà ajouté.' });
+ return;
+ }
+ users = [...users, { displayName: userId, avatar: '/img/default-avatar.png' } as IUser];
+ }}
+ />
+</div>
diff --git a/ping/frontend/src/lib/pages.ts b/ping/frontend/src/lib/pages.ts
new file mode 100644
index 0000000..e5d424e
--- /dev/null
+++ b/ping/frontend/src/lib/pages.ts
@@ -0,0 +1,54 @@
+interface SideBarItem {
+ icon: string;
+ name: string;
+ href: string;
+}
+
+export const pages: SideBarItem[] = [
+ {
+ name: 'Dashboard',
+ icon: '/icons/dashboard.svg',
+ href: '/dashboard'
+ },
+ {
+ name: 'Transactions',
+ icon: '/icons/credit-card.svg',
+ href: '/dashboard/transactions'
+ },
+ {
+ name: 'Modèles',
+ icon: '/icons/floppy-disk.svg',
+ href: '/dashboard/models'
+ },
+ {
+ name: 'Analyses',
+ icon: '/icons/magnifying_glass_icon.svg',
+ href: '/dashboard/analyses'
+ },
+ {
+ name: 'Personnel',
+ icon: '/icons/people.svg',
+ href: '/dashboard/personnel'
+ },
+ {
+ name: 'Messages',
+ icon: '/icons/msg.svg',
+ href: '/dashboard/messages'
+ },
+ {
+ name: 'Paramètres',
+ icon: '/icons/settings.svg',
+ href: '/dashboard/settings'
+ }
+];
+
+export function getPageIndex(pathname: string) {
+ if (pathname === '/dashboard') return 0;
+ if (pathname.startsWith('/dashboard/transactions')) return 1;
+ if (pathname.startsWith('/dashboard/models')) return 2;
+ if (pathname.startsWith('/dashboard/analyses')) return 3;
+ if (pathname.startsWith('/dashboard/personnel')) return 4;
+ if (pathname.startsWith('/dashboard/messages')) return 5;
+ if (pathname.startsWith('/dashboard/settings')) return 6;
+ return -1; // Not found
+} \ No newline at end of file
diff --git a/ping/frontend/src/lib/stores/auth.ts b/ping/frontend/src/lib/stores/auth.ts
new file mode 100644
index 0000000..97acaf2
--- /dev/null
+++ b/ping/frontend/src/lib/stores/auth.ts
@@ -0,0 +1,66 @@
+import { error } from "@sveltejs/kit";
+import { get, writable } from "svelte/store";
+
+export interface IUser {
+ id: string;
+ login: string;
+ displayName: string;
+ avatar: string;
+ isAdmin: boolean;
+}
+
+export const user = writable<IUser | null>(null);
+
+export async function getUser() {
+ const userVal = get(user);
+ if (userVal) {
+ return userVal;
+ }
+ return getUpdatedUser();
+}
+
+export async function getUpdatedUser() {
+ const token = localStorage.getItem("token");
+ if (!token) {
+ localStorage.clear();
+ window.location.replace("/login");
+ throw new Error("Pas de token");
+ }
+ try {
+ const userId = JSON.parse(atob(token.split(".")[1])).sub;
+
+ const res = await authFetch(`/api/user/${userId}`);
+ if (!res.ok) {
+ throw error(res.status, "Erreur lors de la récupération de l'utilisateur");
+ }
+ const data = await res.json();
+ user.set({ ...data });
+ return data;
+ }
+ catch (e) {
+ console.error("Erreur lors de la récupération de l'ID utilisateur depuis le token", e);
+ localStorage.clear();
+ window.location.replace("/login");
+ throw new Error("Token invalide " + e);
+ }
+}
+
+// place files you want to import through the `$lib` alias in this folder.
+export function authFetch(url: string | URL, options: RequestInit = {}) {
+ const token = localStorage.getItem("token");
+ if (!token) {
+ localStorage.clear();
+ window.location.replace("/login");
+ throw new Error("Pas de token");
+ }
+
+ const mergedOptions: RequestInit = {
+ ...options,
+ headers: {
+ Authorization: `Bearer ${token}`,
+ ...(options.headers ?? {})
+ }
+ };
+
+ return fetch(url, mergedOptions);
+} \ No newline at end of file
diff --git a/ping/frontend/src/lib/stores/toast.ts b/ping/frontend/src/lib/stores/toast.ts
new file mode 100644
index 0000000..454461b
--- /dev/null
+++ b/ping/frontend/src/lib/stores/toast.ts
@@ -0,0 +1,22 @@
+import { writable } from "svelte/store";
+
+export interface Toast {
+ color?: string | undefined;
+ title?: string | undefined;
+ message?: string | undefined;
+}
+
+export const toastList = writable<Toast[]>([]);
+
+export function addToast(toast: Toast) {
+ toast ??= { color: "red", title: "Error", message: "An error occurred" };
+ toast.color ??= "red";
+ toast.title ??= "Error";
+ toast.message ??= "An error occurred";
+
+ toastList.update((list) => [...list, toast]);
+
+ setTimeout(() => {
+ toastList.update((list) => list.filter((t) => t !== toast));
+ }, 5000);
+} \ No newline at end of file
diff --git a/ping/frontend/src/routes/+layout.svelte b/ping/frontend/src/routes/+layout.svelte
new file mode 100644
index 0000000..ba995cc
--- /dev/null
+++ b/ping/frontend/src/routes/+layout.svelte
@@ -0,0 +1,9 @@
+<script lang="ts">
+ import ToastList from '$lib/components/ToastList.svelte';
+ import '../app.css';
+
+ let { children } = $props();
+</script>
+
+{@render children()}
+<ToastList />
diff --git a/ping/frontend/src/routes/+page.svelte b/ping/frontend/src/routes/+page.svelte
new file mode 100644
index 0000000..7088945
--- /dev/null
+++ b/ping/frontend/src/routes/+page.svelte
@@ -0,0 +1,59 @@
+<script lang="ts">
+ import Button from '$lib/components/Button.svelte';
+ import NavBar from '$lib/components/NavBar.svelte';
+</script>
+
+<NavBar pageTitle="">
+ <!-- Composant gauche de la navbar -->
+ {#snippet rightComponent()}
+ <Button href="/login">Connexion</Button>
+ {/snippet}
+</NavBar>
+<header></header>
+<section class="colored"></section>
+<section id="bottomcard">
+ <div class="card">
+ <h1>Investissons <b>plus mieux</b> et <b>plus vert</b></h1>
+ <ul>
+ <li>Investissez facilement</li>
+ <li>Analysez les risques et les performances</li>
+ <li>Soulagez votre éco-conscience</li>
+ </ul>
+ </div>
+</section>
+
+<style>
+ header {
+ background-image: url('/img/header-bg.jpg');
+ height: 80vh;
+ background-size: cover;
+ background-position: center;
+ }
+
+ .colored {
+ background-color: var(--bg-secondary);
+ height: 20vh;
+ }
+
+ #bottomcard {
+ position: fixed;
+ bottom: 10vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: white;
+ }
+
+ #bottomcard h1 {
+ font-size: 2em;
+ margin-bottom: 10px;
+ color: var(--text-lime);
+ }
+
+ #bottomcard ul {
+ list-style: square;
+ padding: 0;
+ margin: 0;
+ margin-left: 20px;
+ }
+</style>
diff --git a/ping/frontend/src/routes/dashboard/+layout.svelte b/ping/frontend/src/routes/dashboard/+layout.svelte
new file mode 100644
index 0000000..a2f7efe
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/+layout.svelte
@@ -0,0 +1,44 @@
+<script lang="ts">
+ import ToastList from '$lib/components/ToastList.svelte';
+ import Avatar from '$lib/components/Avatar.svelte';
+ import NavBar from '$lib/components/NavBar.svelte';
+ import NumberStatList from '$lib/components/NumberStatList.svelte';
+ import SideBar from '$lib/components/SideBar.svelte';
+
+ import '../../app.css';
+ import { getPageIndex, pages } from '$lib/pages';
+ import { onMount } from 'svelte';
+ import { page } from '$app/stores';
+ import { user } from '$lib/stores/auth';
+
+ let { children } = $props();
+
+ let selectedIndex = $state(0);
+
+ $effect(() => {
+ selectedIndex = getPageIndex($page.url.pathname);
+ });
+</script>
+
+<ToastList />
+<NavBar pageTitle={pages[selectedIndex].name}>
+ {#snippet rightComponent()}
+ <div class="flex items-center gap-4">
+ <form>
+ <input type="search" name="search" id="search" placeholder="Search..." />
+ </form>
+ <Avatar username={$user?.login ?? 'No auth'} url={$user?.avatar} />
+ </div>
+ {/snippet}
+</NavBar>
+<SideBar bind:selectedIndex />
+<section class="dashboard">{@render children()}</section>
+
+<style>
+ section.dashboard {
+ padding-left: 208px;
+ padding-top: 72px;
+ width: 100%;
+ height: calc(100vh);
+ }
+</style>
diff --git a/ping/frontend/src/routes/dashboard/+page.svelte b/ping/frontend/src/routes/dashboard/+page.svelte
new file mode 100644
index 0000000..c38e281
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/+page.svelte
@@ -0,0 +1,81 @@
+<script lang="ts">
+ import NumberStatList from '$lib/components/NumberStatList.svelte';
+ import type { INumberStatList } from '$lib/components/NumberStatList.svelte';
+ import RiskAnalysis from '$lib/components/dashboard/RiskAnalysis.svelte';
+ import StockGraph from '$lib/components/dashboard/StockGraph.svelte';
+ import TrendingSymbols from '$lib/components/dashboard/TrendingSymbols.svelte';
+ import { onMount } from 'svelte';
+
+ const statsList: INumberStatList[] = [
+ {
+ name: 'Portefeuille',
+ color: 'aqua',
+ value: `${Math.random().toFixed(3) * 1000}€`,
+ icon: '/icons/wallet.svg'
+ },
+ {
+ name: 'Revenus',
+ color: '#1FCB4F',
+ value: `${Math.random().toFixed(3) * 1000}€`,
+ icon: '/icons/money-bills.svg'
+ },
+ {
+ name: 'Depenses',
+ color: 'orange',
+ value: `${Math.random().toFixed(3) * 1000}€`,
+ icon: '/icons/credit-card.svg'
+ },
+ {
+ name: 'Eco score',
+ color: '#1FCB4F',
+ value: `${Math.random().toFixed(3) * 1000}`,
+ icon: '/icons/leaf.svg'
+ }
+ ];
+
+ onMount(() => {});
+</script>
+
+<section class="dashboard-home">
+ <NumberStatList {statsList} />
+ <div class="home-grid">
+ <div class="card overviewGraph">
+ <StockGraph />
+ </div>
+ <!-- <div class="card riskAnalysis">
+ <RiskAnalysis />
+ </div> -->
+ <!-- <div class="card activity">c</div> -->
+ <div class="card tendencies">
+ <TrendingSymbols />
+ </div>
+ <!-- <div class="card recentInvestments">e</div> -->
+ </div>
+</section>
+
+<style>
+ .home-grid {
+ display: grid;
+ grid-template-areas:
+ 'overviewGraph overviewGraph overviewGraph'
+ 'tendencies tendencies tendencies';
+ gap: 16px;
+ width: calc(100% - 32px);
+ }
+
+ .overviewGraph {
+ grid-area: overviewGraph;
+ }
+ /* .riskAnalysis {
+ grid-area: riskAnalysis;
+ }
+ .activity {
+ grid-area: activity;
+ } */
+ .tendencies {
+ grid-area: tendencies;
+ }
+ /* .recentInvestments {
+ grid-area: recentInvestments;
+ } */
+</style>
diff --git a/ping/frontend/src/routes/dashboard/analyses/+page.svelte b/ping/frontend/src/routes/dashboard/analyses/+page.svelte
new file mode 100644
index 0000000..1a8ed47
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/analyses/+page.svelte
@@ -0,0 +1,409 @@
+<script lang="ts">
+ import type { INumberStatList } from '$lib/components/NumberStatList.svelte';
+ import NumberStatList from '$lib/components/NumberStatList.svelte';
+ import SteppedLineChart from '$lib/components/SteppedLineChart.svelte';
+ import { onMount } from 'svelte';
+
+ interface Transaction {
+ id: number;
+ date: Date;
+ amount: number;
+ type: 'buy' | 'sell';
+ recipient: string;
+ company: string;
+ co2Impact: number;
+ }
+
+ const mockTransactions: Transaction[] = [
+ { id: 1, date: new Date('2025-06-20'), amount: 1200, type: 'buy', recipient: 'Microsoft Corp', company: 'MSFT', co2Impact: 45 },
+ { id: 2, date: new Date('2025-06-22'), amount: -800, type: 'sell', recipient: 'Apple Inc', company: 'AAPL', co2Impact: -30 },
+ { id: 3, date: new Date('2025-06-24'), amount: 2500, type: 'buy', recipient: 'Tesla Inc', company: 'TSLA', co2Impact: 15 },
+ { id: 4, date: new Date('2025-06-26'), amount: 950, type: 'buy', recipient: 'Amazon', company: 'AMZN', co2Impact: 60 },
+ { id: 5, date: new Date('2025-06-28'), amount: -1500, type: 'sell', recipient: 'Google', company: 'GOOGL', co2Impact: -40 },
+ { id: 6, date: new Date('2025-06-30'), amount: 750, type: 'buy', recipient: 'Netflix', company: 'NFLX', co2Impact: 25 },
+ { id: 7, date: new Date('2025-07-01'), amount: 1800, type: 'buy', recipient: 'Microsoft Corp', company: 'MSFT', co2Impact: 50 },
+ { id: 8, date: new Date('2025-06-15'), amount: -600, type: 'sell', recipient: 'Tesla Inc', company: 'TSLA', co2Impact: -10 },
+ { id: 9, date: new Date('2025-06-18'), amount: 3200, type: 'buy', recipient: 'NVIDIA', company: 'NVDA', co2Impact: 80 },
+ { id: 10, date: new Date('2025-06-25'), amount: 450, type: 'buy', recipient: 'Apple Inc', company: 'AAPL', co2Impact: 20 }
+ ];
+
+ let transactions = mockTransactions;
+ let selectedPeriod = 30;
+ let analysisData: any = {};
+
+ const thresholds = {
+ dailySpendingLimit: 1000,
+ monthlySpendingLimit: 5000,
+ co2Limit: 100,
+ profitTarget: 2000
+ };
+
+ function calculateStats() {
+ const now = new Date();
+ const cutoffDate = new Date(now.getTime() - selectedPeriod * 24 * 60 * 60 * 1000);
+ const filteredTransactions = transactions.filter(t => t.date >= cutoffDate);
+
+ const totalAmount = filteredTransactions.reduce((sum, t) => sum + t.amount, 0);
+ const averageAmount = filteredTransactions.length > 0 ? totalAmount / filteredTransactions.length : 0;
+ const uniqueRecipients = new Set(filteredTransactions.map(t => t.recipient)).size;
+ const totalCO2 = filteredTransactions.reduce((sum, t) => sum + t.co2Impact, 0);
+
+ const recipientTotals = filteredTransactions.reduce((acc, t) => {
+ acc[t.recipient] = (acc[t.recipient] || 0) + t.amount;
+ return acc;
+ }, {} as Record<string, number>);
+
+ const dailyData = filteredTransactions.reduce((acc, t) => {
+ const date = t.date.toISOString().split('T')[0];
+ acc[date] = (acc[date] || 0) + t.amount;
+ return acc;
+ }, {} as Record<string, number>);
+
+ const chartData = Object.entries(dailyData)
+ .map(([date, amount]) => ({
+ label: new Date(date).toLocaleDateString('fr-FR', { month: 'short', day: 'numeric' }),
+ value: amount
+ }))
+ .sort((a, b) => a.label.localeCompare(b.label));
+
+ const recipientChartData = Object.entries(recipientTotals).map(([recipient, total]) => ({
+ x: recipient,
+ y: Math.abs(total)
+ })).sort((a, b) => b.y - a.y);
+
+ const thresholdAlerts = {
+ dailySpending: Math.abs(totalAmount / selectedPeriod) > thresholds.dailySpendingLimit,
+ monthlySpending: Math.abs(totalAmount * (30 / selectedPeriod)) > thresholds.monthlySpendingLimit,
+ co2Impact: totalCO2 > thresholds.co2Limit,
+ profitTarget: totalAmount >= thresholds.profitTarget
+ };
+
+ analysisData = {
+ totalAmount,
+ averageAmount,
+ uniqueRecipients,
+ totalCO2,
+ chartData,
+ recipientChartData,
+ thresholdAlerts,
+ filteredTransactions
+ };
+ }
+
+ $: statsList = [
+ {
+ name: 'Total Transactions',
+ color: 'aqua',
+ value: `${analysisData.totalAmount ? analysisData.totalAmount.toFixed(0) : '0'}€`,
+ icon: '/icons/wallet.svg'
+ },
+ {
+ name: 'Moyenne',
+ color: '#1FCB4F',
+ value: `${analysisData.averageAmount ? analysisData.averageAmount.toFixed(0) : '0'}€`,
+ icon: '/icons/money-bills.svg'
+ },
+ {
+ name: 'Destinataires',
+ color: 'orange',
+ value: `${analysisData.uniqueRecipients || 0}`,
+ icon: '/icons/people.svg'
+ },
+ {
+ name: 'Impact CO2',
+ color: analysisData.totalCO2 > 0 ? '#ff6b6b' : '#1FCB4F',
+ value: `${analysisData.totalCO2 ? analysisData.totalCO2.toFixed(0) : '0'}g`,
+ icon: '/icons/leaf.svg'
+ }
+ ];
+
+ onMount(() => calculateStats());
+ $: selectedPeriod && calculateStats();
+</script>
+
+<section id="analyses">
+ <div class="controls">
+ <h1>Analyses des Transactions</h1>
+ <div class="period-selector">
+ <label for="period">Période d'analyse:</label>
+ <select bind:value={selectedPeriod} id="period">
+ <option value={7}>7 derniers jours</option>
+ <option value={30}>30 derniers jours</option>
+ <option value={90}>3 derniers mois</option>
+ <option value={365}>1 an</option>
+ </select>
+ </div>
+ </div>
+
+ <NumberStatList {statsList} />
+
+ {#if analysisData.thresholdAlerts}
+ <div class="threshold-alerts">
+ {#if analysisData.thresholdAlerts.dailySpending}
+ <div class="alert alert-warning">
+ ⚠️ Dépenses quotidiennes élevées ({(Math.abs(analysisData.totalAmount) / selectedPeriod).toFixed(0)}€/jour)
+ </div>
+ {/if}
+ {#if analysisData.thresholdAlerts.co2Impact}
+ <div class="alert alert-danger">
+ 🌍 Impact CO2 élevé ({analysisData.totalCO2}g)
+ </div>
+ {/if}
+ {#if analysisData.thresholdAlerts.profitTarget}
+ <div class="alert alert-success">
+ 🎯 Objectif de profit atteint ({analysisData.totalAmount.toFixed(0)}€)
+ </div>
+ {/if}
+ </div>
+ {/if}
+
+ <div id="analysis-grid">
+ <div class="card">
+ <h3>Transactions dans le temps</h3>
+ {#if analysisData.chartData?.length > 0}
+ <SteppedLineChart color="#1FCB4F" data={analysisData.chartData} title="Évolution" legend="Montant (€)" />
+ {:else}
+ <p style="color: #888; text-align: center; padding: 20px;">Aucune donnée</p>
+ {/if}
+ </div>
+
+ <div class="card">
+ <h3>Top destinataires</h3>
+ <div class="recipients-chart">
+ {#each (analysisData.recipientChartData || []).slice(0, 5) as recipient}
+ <div class="recipient-bar">
+ <span class="recipient-name">{recipient.x}</span>
+ <div class="bar-container">
+ {#if analysisData.recipientChartData?.length > 0}
+ {@const maxValue = Math.max(...analysisData.recipientChartData.map(r => r.y))}
+ <div class="bar" style="width: {(recipient.y / maxValue) * 100}%"></div>
+ {:else}
+ <div class="bar" style="width: 0%"></div>
+ {/if}
+ <span class="recipient-amount">{recipient.y.toFixed(0)}€</span>
+ </div>
+ </div>
+ {/each}
+ </div>
+ </div>
+
+ <div class="card">
+ <h3>Répartition des transactions</h3>
+ <div class="transaction-breakdown">
+ <div class="breakdown-item">
+ <span class="breakdown-label">Achats:</span>
+ <span class="breakdown-value positive">
+ {(analysisData.filteredTransactions || []).filter((t: Transaction) => t.type === 'buy').length}
+ </span>
+ </div>
+ <div class="breakdown-item">
+ <span class="breakdown-label">Ventes:</span>
+ <span class="breakdown-value negative">
+ {(analysisData.filteredTransactions || []).filter((t: Transaction) => t.type === 'sell').length}
+ </span>
+ </div>
+ <div class="breakdown-item">
+ <span class="breakdown-label">Volume total:</span>
+ <span class="breakdown-value">
+ {Math.abs(analysisData.totalAmount || 0).toFixed(0)}€
+ </span>
+ </div>
+ </div>
+ </div>
+
+ <div class="card">
+ <h3>Métriques CO2</h3>
+ <div class="co2-metrics">
+ <div class="co2-item">
+ <span class="co2-label">Impact total:</span>
+ <span class="co2-value {analysisData.totalCO2 > 0 ? 'negative' : 'positive'}">
+ {analysisData.totalCO2 || 0}g CO2
+ </span>
+ </div>
+ <div class="co2-item">
+ <span class="co2-label">Par transaction:</span>
+ <span class="co2-value">
+ {(analysisData.filteredTransactions?.length ? analysisData.totalCO2 / analysisData.filteredTransactions.length : 0).toFixed(1)}g
+ </span>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
+
+<style>
+ .card {
+ margin: 0;
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ padding: 16px;
+ color: white;
+ }
+
+ .card h3 {
+ margin: 0 0 16px 0;
+ color: var(--text-lime);
+ font-size: 18px;
+ font-weight: 600;
+ }
+
+ #analyses {
+ display: flex;
+ flex-direction: column;
+ padding-right: 12px;
+ background-color: var(--bg-secondary);
+ min-height: calc(100vh - 72px);
+ color: white;
+ }
+
+ .controls {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 16px 12px;
+ margin-bottom: 8px;
+ }
+
+ .controls h1 {
+ color: var(--text-lime);
+ font-size: 32px;
+ margin: 0;
+ font-weight: 600;
+ }
+
+ .period-selector {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .period-selector label {
+ font-size: 14px;
+ color: white;
+ }
+
+ .period-selector select {
+ background-color: var(--bg-primary);
+ color: white;
+ border: 1px solid #444;
+ border-radius: 4px;
+ padding: 8px 12px;
+ font-size: 14px;
+ }
+
+ .threshold-alerts {
+ padding: 0 12px;
+ margin-bottom: 16px;
+ }
+
+ .alert {
+ padding: 12px 16px;
+ border-radius: 8px;
+ margin-bottom: 8px;
+ font-size: 14px;
+ font-weight: 500;
+ }
+
+ .alert-warning {
+ background-color: rgba(255, 193, 7, 0.2);
+ border-left: 4px solid #ffc107;
+ color: #ffc107;
+ }
+
+ .alert-danger {
+ background-color: rgba(220, 53, 69, 0.2);
+ border-left: 4px solid #dc3545;
+ color: #dc3545;
+ }
+
+ .alert-success {
+ background-color: rgba(40, 167, 69, 0.2);
+ border-left: 4px solid #28a745;
+ color: #28a745;
+ }
+
+ #analysis-grid {
+ padding: 0 12px;
+ width: 100%;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 1rem;
+ }
+
+ .recipients-chart {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ }
+
+ .recipient-bar {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ .recipient-name {
+ font-size: 12px;
+ color: #888;
+ font-weight: 500;
+ }
+
+ .bar-container {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ position: relative;
+ }
+
+ .bar {
+ height: 20px;
+ background: linear-gradient(90deg, var(--text-lime), #1FCB4F);
+ border-radius: 4px;
+ transition: width 0.3s ease;
+ }
+
+ .recipient-amount {
+ font-size: 12px;
+ color: white;
+ font-weight: 600;
+ min-width: 60px;
+ text-align: right;
+ }
+
+ .transaction-breakdown, .co2-metrics {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ }
+
+ .breakdown-item, .co2-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 0;
+ border-bottom: 1px solid #333;
+ }
+
+ .breakdown-item:last-child, .co2-item:last-child {
+ border-bottom: none;
+ }
+
+ .breakdown-label, .co2-label {
+ font-size: 14px;
+ color: #888;
+ }
+
+ .breakdown-value, .co2-value {
+ font-size: 16px;
+ font-weight: 600;
+ color: white;
+ }
+
+ .breakdown-value.positive, .co2-value.positive {
+ color: var(--text-lime);
+ }
+
+ .breakdown-value.negative, .co2-value.negative {
+ color: #ff6b6b;
+ }
+</style>
diff --git a/ping/frontend/src/routes/dashboard/messages/+page.svelte b/ping/frontend/src/routes/dashboard/messages/+page.svelte
new file mode 100644
index 0000000..52869e4
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/messages/+page.svelte
@@ -0,0 +1,403 @@
+<script lang="ts">
+ import type { PageData } from './$types';
+
+ let { data }: { data: PageData } = $props();
+
+ let searchQuery = '';
+ let selectedMessage = null;
+ let newMessage = '';
+ let messages = [
+ {
+ id: 1,
+ sender: 'Équipe Ping',
+ subject: 'Nouvelle analyse de portefeuille disponible',
+ content: 'Votre analyse mensuelle de performance ESG est maintenant disponible. Consultez les dernières métriques de votre portefeuille.',
+ date: new Date('2024-06-28'),
+ unread: true
+ },
+ {
+ id: 2,
+ sender: 'Système',
+ subject: 'Alerte: Score ESG en baisse',
+ content: 'Le score ESG de votre portefeuille a diminué de 5% ce mois-ci. Nous recommandons de réviser vos investissements.',
+ date: new Date('2024-06-25'),
+ unread: true
+ },
+ {
+ id: 3,
+ sender: 'Support',
+ subject: 'Mise à jour des modèles prédictifs',
+ content: 'Nos modèles d\'analyse ont été mis à jour avec les dernières données du marché. Vos prédictions sont maintenant plus précises.',
+ date: new Date('2024-06-20'),
+ unread: false
+ }
+ ];
+
+ function handleSearch() {
+ console.log('Searching messages:', searchQuery);
+ }
+
+ function selectMessage(message: any) {
+ selectedMessage = message;
+ if (message.unread) {
+ message.unread = false;
+ messages = [...messages];
+ }
+ }
+
+ function sendMessage() {
+ if (newMessage.trim()) {
+ console.log('Sending message:', newMessage);
+ newMessage = '';
+ }
+ }
+
+ function deleteMessage(messageId: number) {
+ messages = messages.filter(m => m.id !== messageId);
+ if (selectedMessage?.id === messageId) {
+ selectedMessage = null;
+ }
+ }
+</script>
+
+<section id="messages">
+ <div class="messages-container">
+ <!-- Header -->
+ <div class="messages-header">
+ <h1>Messages</h1>
+ <div class="search-bar">
+ <input
+ type="text"
+ placeholder="Rechercher dans les messages..."
+ bind:value={searchQuery}
+ on:input={handleSearch}
+ />
+ <button class="search-btn">🔍</button>
+ </div>
+ </div>
+
+ <div class="messages-layout">
+ <!-- Messages List -->
+ <div class="messages-list card">
+ <h2>Boîte de réception</h2>
+ <div class="message-items">
+ {#each messages as message}
+ <div
+ class="message-item {message.unread ? 'unread' : ''} {selectedMessage?.id === message.id ? 'selected' : ''}"
+ on:click={() => selectMessage(message)}
+ >
+ <div class="message-header">
+ <span class="message-sender">{message.sender}</span>
+ <span class="message-date">{message.date.toLocaleDateString()}</span>
+ </div>
+ <div class="message-subject">{message.subject}</div>
+ <div class="message-preview">{message.content.substring(0, 80)}...</div>
+ {#if message.unread}
+ <div class="unread-indicator"></div>
+ {/if}
+ </div>
+ {/each}
+ </div>
+ </div>
+
+ <!-- Message Detail -->
+ <div class="message-detail card">
+ {#if selectedMessage}
+ <div class="message-detail-header">
+ <h3>{selectedMessage.subject}</h3>
+ <div class="message-actions">
+ <button class="btn" on:click={() => deleteMessage(selectedMessage.id)}>
+ 🗑️ Supprimer
+ </button>
+ </div>
+ </div>
+ <div class="message-meta">
+ <span>De: {selectedMessage.sender}</span>
+ <span>Date: {selectedMessage.date.toLocaleDateString()}</span>
+ </div>
+ <div class="message-content">
+ {selectedMessage.content}
+ </div>
+
+ <!-- Reply Section -->
+ <div class="reply-section">
+ <h4>Répondre</h4>
+ <textarea
+ bind:value={newMessage}
+ placeholder="Tapez votre réponse..."
+ rows="4"
+ ></textarea>
+ <button class="btn" on:click={sendMessage}>
+ 📤 Envoyer
+ </button>
+ </div>
+ {:else}
+ <div class="no-message-selected">
+ <h3>Sélectionnez un message</h3>
+ <p>Choisissez un message dans la liste pour le lire</p>
+ </div>
+ {/if}
+ </div>
+ </div>
+ </div>
+</section>
+
+<style>
+ #messages {
+ padding: 16px;
+ background-color: var(--bg-secondary);
+ color: white;
+ min-height: calc(100vh - 72px);
+ }
+
+ .messages-container {
+ max-width: 1400px;
+ }
+
+ /* Header */
+ .messages-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ }
+
+ h1 {
+ color: var(--text-lime);
+ font-size: 32px;
+ margin: 0;
+ font-weight: 600;
+ }
+
+ h2 {
+ color: var(--text-lime);
+ font-size: 24px;
+ margin: 0 0 16px 0;
+ font-weight: 600;
+ }
+
+ .search-bar {
+ display: flex;
+ align-items: center;
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ padding: 4px;
+ gap: 8px;
+ }
+
+ .search-bar input {
+ background: transparent;
+ border: none;
+ color: white;
+ padding: 12px 16px;
+ font-size: 14px;
+ outline: none;
+ width: 300px;
+ }
+
+ .search-bar input::placeholder {
+ color: #888888;
+ }
+
+ .search-btn {
+ background: transparent;
+ border: none;
+ color: #888888;
+ padding: 8px;
+ cursor: pointer;
+ font-size: 16px;
+ }
+
+ /* Layout */
+ .messages-layout {
+ display: flex;
+ gap: 16px;
+ height: calc(100vh - 200px);
+ }
+
+ .card {
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 16px;
+ margin: 16px;
+ color: white;
+ }
+
+ /* Messages List */
+ .messages-list {
+ flex: 1;
+ max-width: 400px;
+ }
+
+ .message-items {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ max-height: calc(100vh - 300px);
+ overflow-y: auto;
+ }
+
+ .message-item {
+ padding: 12px;
+ border-radius: 8px;
+ background-color: var(--bg-secondary);
+ cursor: pointer;
+ transition-duration: 0.2s;
+ position: relative;
+ border-left: 3px solid transparent;
+ }
+
+ .message-item:hover {
+ background-color: var(--btn-primary);
+ transform: scale(1.02);
+ }
+
+ .message-item.selected {
+ border-left-color: var(--text-lime);
+ background-color: var(--btn-primary);
+ }
+
+ .message-item.unread {
+ background-color: rgba(0, 255, 119, 0.1);
+ }
+
+ .message-header {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 4px;
+ }
+
+ .message-sender {
+ font-weight: 600;
+ color: var(--text-lime);
+ }
+
+ .message-date {
+ font-size: 12px;
+ color: #888888;
+ }
+
+ .message-subject {
+ font-weight: 500;
+ margin-bottom: 4px;
+ font-size: 14px;
+ }
+
+ .message-preview {
+ font-size: 13px;
+ color: #888888;
+ }
+
+ .unread-indicator {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ width: 8px;
+ height: 8px;
+ background-color: var(--text-lime);
+ border-radius: 50%;
+ }
+
+ /* Message Detail */
+ .message-detail {
+ flex: 2;
+ }
+
+ .message-detail-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ padding-bottom: 16px;
+ border-bottom: 1px solid var(--btn-primary);
+ }
+
+ .message-detail-header h3 {
+ margin: 0;
+ color: white;
+ font-size: 20px;
+ }
+
+ .message-actions {
+ display: flex;
+ gap: 8px;
+ }
+
+ .message-meta {
+ display: flex;
+ gap: 20px;
+ margin-bottom: 20px;
+ font-size: 14px;
+ color: #888888;
+ }
+
+ .message-content {
+ line-height: 1.6;
+ margin-bottom: 30px;
+ padding: 20px;
+ background-color: var(--bg-secondary);
+ border-radius: 8px;
+ }
+
+ .reply-section {
+ border-top: 1px solid var(--btn-primary);
+ padding-top: 20px;
+ }
+
+ .reply-section h4 {
+ margin: 0 0 12px 0;
+ color: var(--text-lime);
+ }
+
+ textarea {
+ width: 100%;
+ background-color: var(--bg-secondary);
+ border: none;
+ border-bottom: 2px solid var(--text-lime);
+ padding: 8px;
+ border-radius: 8px 8px 0 0;
+ color: white;
+ font-size: 14px;
+ resize: vertical;
+ box-sizing: border-box;
+ margin-bottom: 12px;
+ }
+
+ textarea::placeholder {
+ color: #888888;
+ }
+
+ textarea:focus {
+ outline: none;
+ border-bottom-color: var(--text-lime);
+ }
+
+ .no-message-selected {
+ text-align: center;
+ padding: 60px 20px;
+ color: #888888;
+ }
+
+ .no-message-selected h3 {
+ margin: 0 0 12px 0;
+ color: #888888;
+ }
+
+ .btn {
+ background-color: var(--btn-primary);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ text-decoration: none;
+ transition-duration: 0.2s;
+ font-weight: 600;
+ }
+
+ .btn:hover {
+ background-color: var(--btn-primary-hover);
+ transform: scale(1.025);
+ }
+</style>
diff --git a/ping/frontend/src/routes/dashboard/models/+page.svelte b/ping/frontend/src/routes/dashboard/models/+page.svelte
new file mode 100644
index 0000000..3be6f00
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/models/+page.svelte
@@ -0,0 +1,568 @@
+<script lang="ts">
+ import Avatar from '$lib/components/Avatar.svelte';
+ import UserSelector from '$lib/components/input/UserSelector.svelte';
+ import { authFetch, getUser, type IUser } from '$lib/stores/auth';
+ import { addToast } from '$lib/stores/toast';
+ import { onMount } from 'svelte';
+ import { get } from 'svelte/store';
+
+ interface IModel {
+ id: string;
+ members: IUser[];
+ name: string;
+ owner: IUser;
+ }
+
+ let modelName = $state('');
+ let sources = $state([]);
+ let models = $state<IModel[]>([]);
+ let modelToEdit = $state<number | null>(null);
+ let modelOwner = $state<IUser | null>(null);
+
+ let users = $state<IUser[]>([]);
+
+ function addSource() {
+ sources = [...sources, ''];
+ }
+
+ function removeSource(index: number) {
+ sources = sources.filter((_, i) => i !== index);
+ }
+
+ function handleSubmit(e: SubmitEvent) {
+ e.preventDefault();
+ if (modelToEdit === null) {
+ createModel();
+ } else {
+ updateModel();
+ }
+ }
+
+ async function createModel() {
+ try {
+ const response = await authFetch('/api/projects', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ accept: 'application/json'
+ },
+ body: JSON.stringify({
+ name: modelName
+ })
+ });
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const data = await response.json();
+ models = [...models, data];
+ await Promise.all(
+ users.map((user) =>
+ authFetch(`/api/projects/${data.id}/add-user`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ accept: '*/*'
+ },
+ body: JSON.stringify({ userId: user.id })
+ })
+ .then((res) => {
+ if (!res.ok) {
+ addToast({
+ color: 'red',
+ title: 'Erreur',
+ message: `Impossible d'ajouter l'utilisateur ${user.displayName} au modèle "${modelName}".`
+ });
+ console.error(`HTTP error! status: ${res.status}`);
+ }
+ return res.json().catch(() => null);
+ })
+ .then((memberData) => {
+ console.log('Member added:', memberData);
+ })
+ .catch((err) => {
+ console.error('Error adding member:', err);
+ })
+ )
+ );
+ addToast({
+ color: 'green',
+ title: 'Modèle créé',
+ message: `Le modèle "${modelName}" a été créé avec succès.`
+ });
+ modelName = '';
+ return data;
+ } catch (error) {
+ console.error('Error creating model:', error);
+ addToast({
+ color: 'red',
+ title: 'Erreur',
+ message: `Une erreur est survenue lors de la création du modèle "${modelName}".`
+ });
+ throw error;
+ }
+ }
+
+ async function updateModel() {
+ try {
+ if (modelToEdit === null || models.length <= modelToEdit) {
+ addToast({
+ color: 'red',
+ title: 'Erreur',
+ message: 'Aucun modèle sélectionné pour la mise à jour.'
+ });
+ return;
+ }
+ const model = models[modelToEdit];
+ console.log('Updating model:', model);
+ const response = await authFetch(`/api/projects/${model.id}`, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json',
+ accept: 'application/json'
+ },
+ body: JSON.stringify({
+ name: modelName
+ })
+ });
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const updatedModel = await response.json();
+ models = models.map((m, i) => (i === modelToEdit ? updatedModel : m));
+ modelToEdit = null;
+ modelName = '';
+ addToast({
+ color: 'green',
+ title: 'Modèle mis à jour',
+ message: `Le modèle "${updatedModel.name}" a été mis à jour avec succès.`
+ });
+ } catch (error) {
+ console.error('Error updating model:', error);
+ addToast({
+ color: 'red',
+ title: 'Erreur',
+ message: `Une erreur est survenue lors de la mise à jour du modèle "${modelName}".`
+ });
+ throw error;
+ }
+ }
+
+ async function getMyModels() {
+ try {
+ const response = await authFetch('/api/projects', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ accept: 'application/json'
+ }
+ });
+ const data = await response.json();
+ console.log('My models:', data);
+ return data;
+ } catch (error) {
+ console.error('Error fetching models:', error);
+ addToast({
+ color: 'red',
+ title: 'Erreur',
+ message: 'Impossible de charger les modèles.'
+ });
+ throw error;
+ }
+ }
+
+ function deleteModel(i: number) {
+ if (models.length <= i || i < 0) {
+ addToast({
+ color: 'red',
+ title: 'Erreur',
+ message: 'Modèle introuvable.'
+ });
+ return;
+ }
+
+ modelToEdit = null;
+
+ const modelToDelete = models[i];
+ authFetch(`/api/projects/${modelToDelete.id}`, {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json',
+ accept: 'application/json'
+ }
+ })
+ .then(() => {
+ models = models.filter((_, index) => index !== i);
+ addToast({
+ color: 'green',
+ title: 'Modèle supprimé',
+ message: `Le modèle "${modelToDelete.name}" a été supprimé avec succès.`
+ });
+ })
+ .catch((err) => {
+ console.error('Error deleting model:', err);
+ addToast({
+ color: 'red',
+ title: 'Erreur',
+ message: `Impossible de supprimer le modèle "${modelToDelete.name}".`
+ });
+ });
+ }
+
+ function onEditButtonPressed(i: number) {
+ if (modelToEdit === i) {
+ modelToEdit = null;
+ modelName = '';
+ users = [];
+ modelOwner = null;
+ } else {
+ modelToEdit = i;
+ modelName = models[i].name;
+ users = models[i].members || [];
+ modelOwner = models[i].owner || null;
+ }
+ }
+
+ let currentUser = $state<IUser | null>(null);
+
+ onMount(() => {
+ getMyModels()
+ .then((lsModels) => {
+ models = lsModels;
+ console.log('Models loaded:', models);
+ })
+ .catch((err) => {
+ console.error('Error loading models:', err);
+ });
+ getUser()
+ .then((user) => {
+ currentUser = user;
+ console.log('Current user:', currentUser);
+ })
+ .catch((err) => {
+ console.error('Error fetching current user:', err);
+ });
+ });
+</script>
+
+<section id="models">
+ <div class="models-container">
+ <div class="active-models">
+ <h2>Modèles actifs</h2>
+ <div class="models-list">
+ {#each models as m, i}
+ <div class="model-item" class:selected={modelToEdit === i}>
+ <div class="model-name">
+ <span>{m.name}</span><br />
+ <code style="font-size:8px">{m.id}</code>
+ </div>
+ <div class="model-metrics">
+ <div class="metric">
+ <span class="metric-label">Eco score</span>
+ <span class="metric-value green">{69} %</span>
+ </div>
+ <div class="metric">
+ <span class="metric-label">Efficacité</span>
+ <span class="metric-value green">{69} %</span>
+ </div>
+ </div>
+ <button class="modify-btn" onclick={() => onEditButtonPressed(i)}>✏️</button>
+ <button class="delete-btn btn" onclick={() => deleteModel(i)}>🗑️</button>
+ </div>
+ {/each}
+ </div>
+ </div>
+
+ <div class="new-model">
+ <form onsubmit={handleSubmit}>
+ <div class="new-model-header">
+ {#if modelToEdit !== null}
+ <h2>Modifier un modèle</h2>
+ {:else}
+ <h2>Nouveau modèle</h2>
+ {/if}
+ <button class="register-btn" type="submit">📁 Enregistrer</button>
+ </div>
+ <div class="form-group">
+ <label for="name">Nom du modèle</label>
+ <input type="text" id="name" bind:value={modelName} placeholder="Modèle X" />
+ <div class="flex gap-2 p-2">
+ {#if modelToEdit !== null}
+ <Avatar username={modelOwner?.displayName} url={modelOwner?.avatar} />
+ {:else if currentUser}
+ <Avatar username={currentUser.displayName} url={currentUser.avatar} />
+ {:else}
+ Chargement en cours...
+ {/if}
+ <UserSelector bind:users />
+ </div>
+ </div>
+
+ <div class="sources-section">
+ <div class="sources-header">
+ <span>Sources de données</span>
+ <button type="button" class="add-source-btn" onclick={addSource}>
+ ➕ Ajouter une source de données
+ </button>
+ </div>
+
+ {#each sources as source, index}
+ <div class="source-item">
+ <!-- svelte-ignore a11y_label_has_associated_control -->
+ <label>Source {index + 1}</label>
+ <div class="source-input-group">
+ <input type="text" bind:value={sources[index]} placeholder="Source" />
+ <button type="button" class="remove-source-btn" onclick={() => removeSource(index)}>
+ 🗑️
+ </button>
+ </div>
+ </div>
+ {/each}
+ </div>
+ </form>
+ </div>
+ </div>
+</section>
+
+<style>
+ #models {
+ padding: 16px;
+ background-color: var(--bg-secondary);
+ color: white;
+ min-height: calc(100vh - 72px);
+ }
+
+ .models-container {
+ display: flex;
+ gap: 16px;
+ max-width: 1400px;
+ }
+
+ h2 {
+ color: var(--text-lime);
+ font-size: 24px;
+ margin: 0 0 16px 0;
+ font-weight: 600;
+ }
+
+ /* Modèles actifs */
+ .active-models {
+ flex: 1;
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 16px;
+ margin: 16px;
+ color: white;
+ }
+
+ .models-list {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ }
+
+ .model-item {
+ background-color: var(--bg-secondary);
+ padding: 16px;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border: 2px solid transparent;
+ }
+
+ .model-item.selected {
+ border: 2px solid var(--text-lime);
+ }
+
+ .model-name {
+ font-weight: 500;
+ font-size: 16px;
+ color: white;
+ }
+
+ .model-metrics {
+ display: flex;
+ gap: 30px;
+ }
+
+ .metric {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 5px;
+ }
+
+ .metric-label {
+ font-size: 12px;
+ color: #888888;
+ }
+
+ .metric-value {
+ font-size: 18px;
+ font-weight: bold;
+ }
+
+ .metric-value.green {
+ color: var(--text-lime);
+ }
+
+ .modify-btn {
+ background-color: var(--btn-primary);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 600;
+ transition-duration: 0.2s;
+ }
+
+ .modify-btn:hover {
+ background-color: var(--btn-primary-hover);
+ transform: scale(1.025);
+ }
+
+ /* Nouveau modèle */
+ .new-model {
+ flex: 1;
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 16px;
+ margin: 16px;
+ color: white;
+ }
+
+ .new-model-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ }
+
+ .register-btn {
+ background-color: var(--btn-primary);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-weight: 600;
+ font-size: 14px;
+ transition-duration: 0.2s;
+ }
+
+ .register-btn:hover {
+ background-color: var(--btn-primary-hover);
+ transform: scale(1.025);
+ }
+
+ .form-group {
+ margin-bottom: 16px;
+ }
+
+ label {
+ display: block;
+ margin-bottom: 8px;
+ font-size: 14px;
+ color: white;
+ font-weight: 500;
+ }
+
+ input[type='text'] {
+ width: 100%;
+ background-color: var(--bg-secondary);
+ border: none;
+ border-bottom: 2px solid var(--text-lime);
+ padding: 8px;
+ border-radius: 8px 8px 0 0;
+ color: white;
+ font-size: 14px;
+ box-sizing: border-box;
+ }
+
+ input[type='text']:focus {
+ outline: none;
+ border-bottom-color: var(--text-lime);
+ }
+
+ input[type='text']::placeholder {
+ color: #888888;
+ }
+
+ /* Sources section */
+ .sources-section {
+ margin-top: 16px;
+ }
+
+ .sources-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+ }
+
+ .sources-header span {
+ font-size: 14px;
+ font-weight: 500;
+ color: white;
+ }
+
+ .add-source-btn {
+ background-color: var(--btn-secondary);
+ color: var(--text-lime);
+ border: 1px solid var(--text-lime);
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 12px;
+ font-weight: 600;
+ transition-duration: 0.2s;
+ }
+
+ .add-source-btn:hover {
+ background-color: var(--text-lime);
+ color: var(--bg-primary);
+ transform: scale(1.025);
+ }
+
+ .source-item {
+ margin-bottom: 15px;
+ }
+
+ .source-item label {
+ margin-bottom: 6px;
+ font-size: 12px;
+ color: #888888;
+ }
+
+ .source-input-group {
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ }
+
+ .source-input-group input {
+ flex: 1;
+ }
+
+ .remove-source-btn {
+ background-color: var(--btn-secondary);
+ color: #888888;
+ border: none;
+ padding: 8px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 16px;
+ transition-duration: 0.2s;
+ min-width: 40px;
+ }
+
+ .remove-source-btn:hover {
+ color: #ef4444;
+ background-color: var(--btn-primary);
+ transform: scale(1.025);
+ }
+</style>
diff --git a/ping/frontend/src/routes/dashboard/personnel/+page.svelte b/ping/frontend/src/routes/dashboard/personnel/+page.svelte
new file mode 100644
index 0000000..a1722c1
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/personnel/+page.svelte
@@ -0,0 +1,290 @@
+<script lang="ts">
+ import Avatar from '$lib/components/Avatar.svelte';
+ import UserItem from '$lib/components/UserItem.svelte';
+ import { authFetch, getUpdatedUser, getUser, type IUser } from '$lib/stores/auth';
+ import { addToast } from '$lib/stores/toast';
+ import { onMount } from 'svelte';
+
+ let user = $state<IUser | null>(null);
+ let allUsers = $state<IUser[]>([]);
+
+ let idValue = $state<string>('');
+ let urlValue = $state<string>('');
+ let nameValue = $state<string>('');
+ let passwordValue = $state<string>('');
+
+ async function loadUser() {
+ try {
+ user = await getUser();
+ if (!user) {
+ addToast({ title: 'Erreur', message: 'Utilisateur non trouvé.' });
+ return null;
+ }
+ idValue = user.id;
+ urlValue = user.avatar || '';
+ nameValue = user.displayName || '';
+ return user;
+ } catch (error) {
+ user = null;
+ addToast({ title: 'Erreur', message: 'Impossible de charger les informations utilisateur.' });
+ return null;
+ }
+ }
+
+ async function loadAllUsers() {
+ try {
+ const response = await authFetch('/api/user/all');
+ if (!response.ok) {
+ throw new Error('Erreur lors du chargement des utilisateurs');
+ }
+ const users = await response.json();
+ return users;
+ } catch (error) {
+ addToast({ title: 'Erreur', message: 'Impossible de charger la liste des utilisateurs.' });
+ return [];
+ }
+ }
+
+ function onEditUser(event: Event) {
+ event.preventDefault();
+ const form = event.target as HTMLFormElement;
+ const formData = new FormData(form);
+
+ const { id, avatar, username, password } = Object.fromEntries(formData.entries());
+
+ authFetch(`/api/user/${id}`, {
+ method: 'PUT',
+ body: JSON.stringify({
+ avatar: avatar || user?.avatar,
+ displayName: username || user?.displayName,
+ password: password || undefined
+ }),
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then((res) => res.json())
+ .then((data) => {
+ getUpdatedUser().then((updatedUser) => {
+ user = updatedUser;
+ });
+ console.log('Utilisateur mis à jour', data);
+ addToast({
+ title: 'Succès',
+ message: 'Informations utilisateur mises à jour avec succès.',
+ color: 'green'
+ });
+ })
+ .catch((error) => {
+ addToast({
+ title: 'Erreur',
+ message: 'Échec de la mise à jour des informations utilisateur.'
+ });
+ });
+ }
+
+ function onCreateUser(event: Event) {
+ event.preventDefault();
+ const form = event.target as HTMLFormElement;
+ const formData = new FormData(form);
+ const { login, password, isAdmin } = Object.fromEntries(formData.entries());
+
+ authFetch('/api/user', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ login,
+ password,
+ isAdmin: isAdmin === 'on'
+ })
+ })
+ .then(async (res) => {
+ if (!res.ok) {
+ addToast({
+ title: 'Erreur',
+ message: "Impossible de créer l'utilisateur."
+ });
+ throw new Error("Erreur lors de la création de l'utilisateur");
+ }
+ const newUser = await res.json();
+ allUsers = [...allUsers, newUser];
+ addToast({
+ title: 'Succès',
+ message: 'Nouvel utilisateur créé avec succès.',
+ color: 'green'
+ });
+ form.reset();
+ })
+ .catch(() => {
+ addToast({
+ title: 'Erreur',
+ message: "Impossible de créer l'utilisateur."
+ });
+ });
+ }
+
+ onMount(async () => {
+ loadUser().then((user) => {
+ if (user && user.isAdmin)
+ loadAllUsers().then((users) => {
+ allUsers = users;
+ });
+ });
+ });
+</script>
+
+{#if user}
+ <div id="personnel">
+ <div>
+ <section id="myUser" class="card">
+ <h2>Mon compte</h2>
+ <Avatar username={user.displayName} url={user.avatar || '/img/default-avatar.png'} />
+ <p><b>Nom</b>: {user.displayName}</p>
+ <p><b>Login</b>: {user.login}</p>
+ <p><b>Role</b>: {user.isAdmin ? 'ADMIN' : 'USER'}</p>
+ <p><b>Id</b>: {user.id}</p>
+ </section>
+ <section id="userEdit" class="card">
+ <h2>Modifier</h2>
+ <i
+ >Laisser vide pour ne pas modifier<br />
+ {#if user.isAdmin}
+ <p>Vous pouvez modifier les informations de n'importe quel utilisateur.</p>
+ {:else}
+ <p>Vous ne pouvez modifier que vos propres informations.</p>
+ {/if}
+ </i><br />
+ <form onsubmit={onEditUser}>
+ {#if user.isAdmin}
+ <label for="id">ID de l'utilisateur</label>
+ <input type="text" placeholder="ID de l'utilisateur" name="id" bind:value={idValue} />
+ {/if}
+ <label for="id">URL de l'avatar</label>
+ <input type="text" placeholder="URL de l'avatar" name="avatar" bind:value={urlValue} />
+ <label for="id">Nom d'utilisateur</label>
+ <input
+ type="text"
+ placeholder="Nom d'utilisateur"
+ name="username"
+ bind:value={nameValue}
+ />
+ <label for="id">Mot de passe</label>
+ <input
+ type="password"
+ placeholder="Mot de passe"
+ name="password"
+ bind:value={passwordValue}
+ />
+ <button type="submit" class="btn">Modifier</button>
+ </form>
+ </section>
+ </div>
+
+ {#if user.isAdmin}
+ <section id="adminActions">
+ <div class="card">
+ <h2>Créer un nouvel utilisateur</h2>
+ <form class="flex flex-col gap-2" onsubmit={onCreateUser}>
+ <label for="new-login">Login</label>
+ <input type="text" id="new-login" name="login" placeholder="Login" required />
+
+ <label for="new-password">Mot de passe</label>
+ <input
+ type="password"
+ id="new-password"
+ name="password"
+ placeholder="Mot de passe"
+ required
+ />
+
+ <label for="new-isAdmin">
+ <input type="checkbox" id="new-isAdmin" name="isAdmin" />
+ Administrateur
+ </label>
+
+ <button type="submit" class="btn">Créer</button>
+ </form>
+ </div>
+ <div class="card">
+ <h2>Liste des utilisateurs</h2>
+ <div>
+ {#each allUsers as u}
+ <UserItem
+ user={u}
+ onEdit={() => {
+ idValue = u.id;
+ urlValue = u.avatar || '';
+ nameValue = u.displayName || '';
+ }}
+ onDelete={() => {
+ authFetch(`/api/user/${u.id}`, {
+ method: 'DELETE'
+ })
+ .then(async (res) => {
+ if (!res.ok) {
+ addToast({
+ title: 'Erreur',
+ message: "Impossible de supprimer l'utilisateur."
+ });
+ throw new Error("Erreur lors de la suppression de l'utilisateur");
+ }
+ allUsers = allUsers.filter((user) => user.id !== u.id);
+ addToast({
+ title: 'Succès',
+ message: 'Utilisateur supprimé avec succès.',
+ color: 'green'
+ });
+ })
+ .catch(() => {
+ addToast({
+ title: 'Erreur',
+ message: "Impossible de supprimer l'utilisateur."
+ });
+ });
+ }}
+ />
+ {/each}
+ </div>
+ </div>
+ </section>
+ {/if}
+ </div>
+{:else}
+ <p>Chargement des informations utilisateur...</p>
+{/if}
+
+<style>
+ * {
+ color: white;
+ }
+
+ #personnel {
+ width: calc(100% - 32px);
+ display: flex;
+ gap: 16px;
+ }
+
+ #personnel > * {
+ flex: 1;
+ }
+
+ #myUser {
+ display: flex;
+ flex-direction: column;
+ }
+
+ #userEdit form {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ h2 {
+ margin: 0;
+ font-size: 1.5em;
+ font-weight: 600;
+ color: var(--text-lime);
+ }
+</style>
diff --git a/ping/frontend/src/routes/dashboard/settings/+page.svelte b/ping/frontend/src/routes/dashboard/settings/+page.svelte
new file mode 100644
index 0000000..99c5d8f
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/settings/+page.svelte
@@ -0,0 +1,452 @@
+<script lang="ts">
+ import type { PageData } from './$types';
+
+ let { data }: { data: PageData } = $props();
+
+ let userProfile = {
+ name: 'Baptiste',
+ email: 'baptiste@ping.com',
+ company: 'Ping Analytics',
+ phone: '+33 6 12 34 56 78'
+ };
+
+ let notifications = {
+ emailAlerts: true,
+ portfolioUpdates: true,
+ esgAlerts: true,
+ marketNews: false,
+ weeklyReports: true
+ };
+
+ let security = {
+ twoFactorAuth: false,
+ sessionTimeout: '30',
+ dataEncryption: true
+ };
+
+ let display = {
+ theme: 'dark',
+ language: 'fr',
+ currency: 'EUR',
+ dateFormat: 'DD/MM/YYYY'
+ };
+
+ let currentPassword = '';
+ let newPassword = '';
+ let confirmPassword = '';
+
+ function saveProfile() {
+ console.log('Saving profile:', userProfile);
+ }
+
+ function saveNotifications() {
+ console.log('Saving notifications:', notifications);
+ }
+
+ function saveSecurity() {
+ console.log('Saving security settings:', security);
+ }
+
+ function saveDisplay() {
+ console.log('Saving display settings:', display);
+ }
+
+ function changePassword() {
+ if (newPassword !== confirmPassword) {
+ alert('Les mots de passe ne correspondent pas');
+ return;
+ }
+ console.log('Changing password');
+ currentPassword = '';
+ newPassword = '';
+ confirmPassword = '';
+ }
+
+ function exportData() {
+ console.log('Exporting user data');
+ }
+
+ function deleteAccount() {
+ if (confirm('Êtes-vous sûr de vouloir supprimer votre compte ? Cette action est irréversible.')) {
+ console.log('Deleting account');
+ }
+ }
+</script>
+
+<section id="settings">
+ <div class="settings-container">
+ <div class="settings-header">
+ <h1>Paramètres</h1>
+ </div>
+
+ <div class="settings-layout">
+ <div class="settings-section card">
+ <h2>👤 Profil utilisateur</h2>
+ <form on:submit|preventDefault={saveProfile}>
+ <div class="form-row">
+ <div class="form-group">
+ <label for="name">Nom complet</label>
+ <input type="text" id="name" bind:value={userProfile.name} />
+ </div>
+ <div class="form-group">
+ <label for="email">Email</label>
+ <input type="email" id="email" bind:value={userProfile.email} />
+ </div>
+ </div>
+ <div class="form-row">
+ <div class="form-group">
+ <label for="company">Entreprise</label>
+ <input type="text" id="company" bind:value={userProfile.company} />
+ </div>
+ <div class="form-group">
+ <label for="phone">Téléphone</label>
+ <input type="tel" id="phone" bind:value={userProfile.phone} />
+ </div>
+ </div>
+ <button type="submit" class="btn">💾 Sauvegarder le profil</button>
+ </form>
+ </div>
+
+ <div class="settings-section card">
+ <h2>🔔 Notifications</h2>
+ <form on:submit|preventDefault={saveNotifications}>
+ <div class="checkbox-group">
+ <label class="checkbox-label">
+ <input type="checkbox" bind:checked={notifications.emailAlerts} />
+ <span>Alertes par email</span>
+ </label>
+ <label class="checkbox-label">
+ <input type="checkbox" bind:checked={notifications.portfolioUpdates} />
+ <span>Mises à jour du portefeuille</span>
+ </label>
+ <label class="checkbox-label">
+ <input type="checkbox" bind:checked={notifications.esgAlerts} />
+ <span>Alertes ESG</span>
+ </label>
+ <label class="checkbox-label">
+ <input type="checkbox" bind:checked={notifications.marketNews} />
+ <span>Actualités du marché</span>
+ </label>
+ <label class="checkbox-label">
+ <input type="checkbox" bind:checked={notifications.weeklyReports} />
+ <span>Rapports hebdomadaires</span>
+ </label>
+ </div>
+ <button type="submit" class="btn">💾 Sauvegarder les notifications</button>
+ </form>
+ </div>
+
+ <div class="settings-section card">
+ <h2>🔒 Sécurité</h2>
+ <form on:submit|preventDefault={saveSecurity}>
+ <div class="form-group">
+ <label class="checkbox-label">
+ <input type="checkbox" bind:checked={security.twoFactorAuth} />
+ <span>Authentification à deux facteurs</span>
+ </label>
+ </div>
+ <div class="form-group">
+ <label for="sessionTimeout">Délai d'expiration de session (minutes)</label>
+ <select id="sessionTimeout" bind:value={security.sessionTimeout}>
+ <option value="15">15 minutes</option>
+ <option value="30">30 minutes</option>
+ <option value="60">1 heure</option>
+ <option value="120">2 heures</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <label class="checkbox-label">
+ <input type="checkbox" bind:checked={security.dataEncryption} disabled />
+ <span>Chiffrement des données (toujours activé)</span>
+ </label>
+ </div>
+ <button type="submit" class="btn">💾 Sauvegarder la sécurité</button>
+ </form>
+
+ <div class="password-section">
+ <h3>Changer le mot de passe</h3>
+ <form on:submit|preventDefault={changePassword}>
+ <div class="form-group">
+ <label for="currentPassword">Mot de passe actuel</label>
+ <input type="password" id="currentPassword" bind:value={currentPassword} />
+ </div>
+ <div class="form-group">
+ <label for="newPassword">Nouveau mot de passe</label>
+ <input type="password" id="newPassword" bind:value={newPassword} />
+ </div>
+ <div class="form-group">
+ <label for="confirmPassword">Confirmer le nouveau mot de passe</label>
+ <input type="password" id="confirmPassword" bind:value={confirmPassword} />
+ </div>
+ <button type="submit" class="btn">🔑 Changer le mot de passe</button>
+ </form>
+ </div>
+ </div>
+
+ <div class="settings-section card">
+ <h2>🎨 Affichage</h2>
+ <form on:submit|preventDefault={saveDisplay}>
+ <div class="form-row">
+ <div class="form-group">
+ <label for="theme">Thème</label>
+ <select id="theme" bind:value={display.theme}>
+ <option value="dark">Sombre</option>
+ <option value="light">Clair</option>
+ <option value="auto">Automatique</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="language">Langue</label>
+ <select id="language" bind:value={display.language}>
+ <option value="fr">Français</option>
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-row">
+ <div class="form-group">
+ <label for="currency">Devise</label>
+ <select id="currency" bind:value={display.currency}>
+ <option value="EUR">EUR (€)</option>
+ <option value="USD">USD ($)</option>
+ <option value="GBP">GBP (£)</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="dateFormat">Format de date</label>
+ <select id="dateFormat" bind:value={display.dateFormat}>
+ <option value="DD/MM/YYYY">DD/MM/YYYY</option>
+ <option value="MM/DD/YYYY">MM/DD/YYYY</option>
+ <option value="YYYY-MM-DD">YYYY-MM-DD</option>
+ </select>
+ </div>
+ </div>
+ <button type="submit" class="btn">💾 Sauvegarder l'affichage</button>
+ </form>
+ </div>
+
+ <div class="settings-section card">
+ <h2>📊 Gestion des données</h2>
+ <div class="data-actions">
+ <div class="action-item">
+ <div class="action-info">
+ <h3>Exporter mes données</h3>
+ <p>Téléchargez toutes vos données personnelles dans un fichier JSON</p>
+ </div>
+ <button class="btn" on:click={exportData}>📥 Exporter</button>
+ </div>
+ <div class="action-item danger">
+ <div class="action-info">
+ <h3>Supprimer mon compte</h3>
+ <p>Supprimez définitivement votre compte et toutes vos données</p>
+ </div>
+ <button class="btn danger" on:click={deleteAccount}>🗑️ Supprimer</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
+
+<style>
+ #settings {
+ padding: 16px;
+ background-color: var(--bg-secondary);
+ color: white;
+ min-height: calc(100vh - 72px);
+ }
+
+ .settings-container {
+ max-width: 1200px;
+ }
+
+ .settings-header {
+ margin-bottom: 16px;
+ }
+
+ h1 {
+ color: var(--text-lime);
+ font-size: 32px;
+ margin: 0;
+ font-weight: 600;
+ }
+
+ h2 {
+ color: var(--text-lime);
+ font-size: 24px;
+ margin: 0 0 20px 0;
+ font-weight: 600;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ h3 {
+ color: white;
+ font-size: 18px;
+ margin: 20px 0 12px 0;
+ font-weight: 500;
+ }
+
+ .settings-layout {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+ }
+
+ .settings-section {
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 16px;
+ margin: 16px;
+ color: white;
+ width: calc(100% - 32px);
+ }
+
+ .form-row {
+ display: flex;
+ gap: 20px;
+ margin-bottom: 16px;
+ }
+
+ .form-group {
+ flex: 1;
+ margin-bottom: 16px;
+ }
+
+ label {
+ display: block;
+ margin-bottom: 8px;
+ font-size: 14px;
+ color: white;
+ font-weight: 500;
+ }
+
+ input[type="text"],
+ input[type="email"],
+ input[type="tel"],
+ input[type="password"],
+ select {
+ width: 100%;
+ background-color: var(--bg-secondary);
+ border: none;
+ border-bottom: 2px solid var(--text-lime);
+ padding: 8px;
+ border-radius: 8px 8px 0 0;
+ color: white;
+ font-size: 14px;
+ box-sizing: border-box;
+ }
+
+ input:focus,
+ select:focus {
+ outline: none;
+ border-bottom-color: var(--text-lime);
+ }
+
+ input::placeholder {
+ color: #888888;
+ }
+
+ .checkbox-group {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ margin-bottom: 20px;
+ }
+
+ .checkbox-label {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ cursor: pointer;
+ font-size: 14px;
+ }
+
+ input[type="checkbox"] {
+ width: 18px;
+ height: 18px;
+ accent-color: var(--text-lime);
+ }
+
+ input[type="checkbox"]:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+
+ .btn {
+ background-color: var(--btn-primary);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ text-decoration: none;
+ transition-duration: 0.2s;
+ font-weight: 600;
+ font-size: 14px;
+ }
+
+ .btn:hover {
+ background-color: var(--btn-primary-hover);
+ transform: scale(1.025);
+ }
+
+ .btn.danger {
+ background-color: #dc2626;
+ }
+
+ .btn.danger:hover {
+ background-color: #b91c1c;
+ }
+
+ .password-section {
+ border-top: 1px solid var(--btn-primary);
+ padding-top: 20px;
+ margin-top: 20px;
+ }
+
+ .data-actions {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ }
+
+ .action-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 16px;
+ background-color: var(--bg-secondary);
+ border-radius: 8px;
+ }
+
+ .action-item.danger {
+ border-left: 4px solid #dc2626;
+ }
+
+ .action-info h3 {
+ margin: 0 0 4px 0;
+ font-size: 16px;
+ }
+
+ .action-info p {
+ margin: 0;
+ font-size: 14px;
+ color: #888888;
+ }
+
+ @media (max-width: 768px) {
+ .form-row {
+ flex-direction: column;
+ }
+
+ .action-item {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 12px;
+ }
+ }
+</style>
diff --git a/ping/frontend/src/routes/dashboard/transactions/+page.svelte b/ping/frontend/src/routes/dashboard/transactions/+page.svelte
new file mode 100644
index 0000000..86f9292
--- /dev/null
+++ b/ping/frontend/src/routes/dashboard/transactions/+page.svelte
@@ -0,0 +1,360 @@
+<script lang="ts">
+ import TransactionModal from '$lib/components/dashboard/transactions/TransactionModal.svelte';
+ import { authFetch } from '$lib/stores/auth';
+ import { addToast } from '$lib/stores/toast';
+ import { onMount } from 'svelte';
+
+ interface ITransaction {
+ id: string;
+ label: string | null;
+ amount: number;
+ currency: string;
+ receiverLabel: string | null;
+ receiverIban: string;
+ operationDate: Date;
+ eco_score: number;
+ creationDate: Date;
+ createrId: string;
+ }
+
+ let searchQuery = $state('');
+ let sortBy = $state('Date');
+ let sortOrder = $state('Montant');
+ let transactions: ITransaction[] = $state([]);
+ let isCreateDialogOpened = $state(false);
+
+ let visibleTransactions = $state<ITransaction[]>([]);
+
+ $effect(() => {
+ const query = searchQuery.toLowerCase();
+ visibleTransactions = transactions.filter((t) => {
+ const matchesLabel = t.label?.toLowerCase().includes(query);
+ const matchesReceiver = t.receiverLabel?.toLowerCase().includes(query);
+ const receiverIban = t.receiverIban?.toLowerCase().includes(query);
+ return matchesLabel || matchesReceiver;
+ });
+ });
+
+ function handleSearch() {
+ console.log('Searching for:', searchQuery);
+ }
+
+ function applyFilters() {
+ console.log('Applying filters:', { sortBy, sortOrder });
+ }
+
+ function analyzeTransaction(transaction: any) {
+ console.log('Analyzing transaction', transaction);
+ }
+
+ async function getAllTransactions(): Promise<ITransaction[]> {
+ const res = await authFetch('/api/transactions', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+ const data = await res.json();
+
+ if (!res.ok) {
+ addToast({ message: data.message, color: 'red', title: 'Erreur' });
+ return [];
+ }
+
+ return data.transactions as ITransaction[];
+ }
+
+ function onCreate(tr: ITransaction) {
+ getAllTransactions().then((transactionsData) => {
+ if (transactionsData) {
+ transactions = transactionsData;
+ }
+ });
+ }
+
+ onMount(() => {
+ getAllTransactions().then((transactionsData) => {
+ if (transactionsData) {
+ transactions = transactionsData;
+ visibleTransactions = transactionsData;
+ console.log(transactions);
+ }
+ });
+ });
+</script>
+
+<section id="transactions">
+ <div class="transactions-container">
+ <div class="transactions-header">
+ <h1>Transactions</h1>
+ <div class="search-bar">
+ <input
+ type="text"
+ placeholder="Recherche..."
+ bind:value={searchQuery}
+ oninput={handleSearch}
+ />
+ <button class="search-btn">🔍</button>
+ </div>
+ </div>
+
+ <div class="filters-section">
+ <div class="filters-left">
+ <span class="filter-label">Trier</span>
+ <div class="filter-group">
+ <select bind:value={sortBy} class="filter-select">
+ <option value="Date">Date</option>
+ <option value="Amount">Montant</option>
+ <option value="Company">Entreprise</option>
+ </select>
+ <select bind:value={sortOrder} class="filter-select">
+ <option value="Montant">Montant</option>
+ <option value="ASC">Croissant</option>
+ <option value="DESC">Décroissant</option>
+ </select>
+ </div>
+ </div>
+ <div>
+ <button
+ class="apply-btn"
+ onclick={() => {
+ isCreateDialogOpened = true;
+ }}
+ >
+ ➕ Créer
+ </button>
+ <button class="apply-btn" onclick={applyFilters}> 📁 Appliquer </button>
+ </div>
+ </div>
+
+ <div class="transactions-list">
+ {#each visibleTransactions as transaction}
+ <div class="transaction-card">
+ <div class="transaction-main">
+ <div class="transaction-info">
+ <h3 class="transaction-type">{transaction.label}</h3>
+ <p class="transaction-company">
+ {transaction.receiverIban} • {transaction.receiverLabel}
+ </p>
+ </div>
+ <div class="transaction-metrics">
+ <div class="metric">
+ <span class="metric-label">CO2</span>
+ <span class="metric-value co2">{transaction.eco_score}</span>
+ </div>
+ <div class="metric">
+ <span class="metric-label">{transaction.currency}</span>
+ <span class="metric-value amount">{transaction.amount}</span>
+ </div>
+ </div>
+ <button class="analyze-btn" onclick={() => analyzeTransaction(transaction)}>
+ ✏️ Analyser
+ </button>
+ </div>
+ </div>
+ {/each}
+ </div>
+ </div>
+</section>
+<TransactionModal bind:isOpen={isCreateDialogOpened} {onCreate} />
+
+<style>
+ #transactions {
+ padding: 16px;
+ background-color: var(--bg-secondary);
+ color: white;
+ min-height: calc(100vh - 72px);
+ }
+
+ .transactions-container {
+ max-width: 1200px;
+ }
+
+ .transactions-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ }
+
+ h1 {
+ color: var(--text-lime);
+ font-size: 32px;
+ margin: 0;
+ font-weight: 600;
+ }
+
+ .search-bar {
+ display: flex;
+ align-items: center;
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ padding: 4px;
+ gap: 8px;
+ }
+
+ .search-bar input {
+ background: transparent;
+ border: none;
+ color: white;
+ padding: 12px 16px;
+ font-size: 14px;
+ outline: none;
+ width: 300px;
+ }
+
+ .search-bar input::placeholder {
+ color: #888888;
+ }
+
+ .search-btn {
+ background: transparent;
+ border: none;
+ color: #888888;
+ padding: 8px;
+ cursor: pointer;
+ font-size: 16px;
+ }
+
+ /* Filters */
+ .filters-section {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ padding: 16px;
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+
+ .filters-left {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ }
+
+ .filter-label {
+ color: white;
+ font-weight: 500;
+ font-size: 14px;
+ }
+
+ .filter-group {
+ display: flex;
+ gap: 10px;
+ }
+
+ .filter-select {
+ background-color: var(--bg-secondary);
+ color: white;
+ border: none;
+ border-bottom: 2px solid var(--text-lime);
+ border-radius: 8px 8px 0 0;
+ padding: 8px 12px;
+ font-size: 14px;
+ cursor: pointer;
+ }
+
+ .filter-select:focus {
+ outline: none;
+ border-bottom-color: var(--text-lime);
+ }
+
+ .apply-btn {
+ background-color: var(--btn-primary);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-weight: 600;
+ font-size: 14px;
+ transition-duration: 0.2s;
+ }
+
+ .apply-btn:hover {
+ background-color: var(--btn-primary-hover);
+ transform: scale(1.025);
+ }
+
+ .transactions-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+ }
+
+ .transaction-card {
+ background-color: var(--bg-primary);
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 16px;
+ margin: 16px;
+ color: white;
+ width: calc(100% - 32px);
+ }
+
+ .transaction-main {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ .transaction-info h3 {
+ margin: 0 0 5px 0;
+ font-size: 18px;
+ font-weight: 600;
+ color: white;
+ }
+
+ .transaction-company {
+ margin: 0;
+ font-size: 14px;
+ color: #888888;
+ }
+
+ .transaction-metrics {
+ display: flex;
+ gap: 40px;
+ }
+
+ .metric {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 5px;
+ }
+
+ .metric-label {
+ font-size: 12px;
+ color: #888888;
+ font-weight: 500;
+ }
+
+ .metric-value {
+ font-size: 24px;
+ font-weight: bold;
+ }
+
+ .metric-value.co2,
+ .metric-value.amount {
+ color: var(--text-lime);
+ }
+
+ .analyze-btn {
+ background-color: var(--btn-primary);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 600;
+ transition-duration: 0.2s;
+ }
+
+ .analyze-btn:hover {
+ background-color: var(--btn-primary-hover);
+ transform: scale(1.025);
+ }
+</style>
diff --git a/ping/frontend/src/routes/login/+page.svelte b/ping/frontend/src/routes/login/+page.svelte
new file mode 100644
index 0000000..0d66f8d
--- /dev/null
+++ b/ping/frontend/src/routes/login/+page.svelte
@@ -0,0 +1,149 @@
+<script lang="ts">
+ import { addToast } from '$lib/stores/toast';
+ import { json } from '@sveltejs/kit';
+
+ let isConnecting = $state(false);
+
+ function onSubmit(event: Event) {
+ event.preventDefault();
+
+ isConnecting = true;
+ const fd = new FormData(event.target as HTMLFormElement);
+ const { login, password } = Object.fromEntries(fd.entries());
+
+ fetch('/api/user/login', {
+ body: JSON.stringify({
+ login,
+ password
+ }),
+ headers: {
+ Accept: '*/*',
+ 'Content-Type': 'application/json'
+ },
+ method: 'POST'
+ })
+ .then(async (res) => {
+ const jsonData = await res.json();
+
+ if (!res.ok) {
+ isConnecting = false;
+ addToast({ message: jsonData.message });
+ return;
+ }
+
+ const { token } = jsonData;
+ localStorage.setItem('token', token);
+ window.location.href = '/dashboard';
+ })
+ .catch((err) => {
+ isConnecting = false;
+ console.error('Error during login:', err);
+ addToast({
+ message: "Une erreur est survenue lors de la connexion. (Plus d'infos dans la console)"
+ });
+ });
+ }
+
+ function createDebugUsers() {
+ fetch('/api/dbdebuguser')
+ .then((res) => {
+ if (res.ok) {
+ res.json().then((data) => {
+ if (data.created) {
+ addToast({
+ message: 'Utilisateurs de debug créés avec succès.',
+ color: 'green',
+ title: 'Succès'
+ });
+ return data;
+ } else {
+ addToast({
+ message: 'Utilisateurs de debug déjà créés.',
+ color: 'green',
+ title: 'Succès'
+ });
+ }
+ });
+ } else {
+ addToast({ message: 'Il semblerait que les utilisateurs de debug soient déjà crées.' });
+ }
+ })
+ .catch((err) => {
+ console.error('Erreur lors de la création des utilisateurs de debug:', err);
+ addToast({
+ message:
+ "Erreur lors de la création des utilisateurs de debug. (Plus d'infos dans la console)"
+ });
+ });
+ }
+</script>
+
+<div class="bg">
+ <div class="card">
+ <h1>Connectez-vous</h1>
+ <form onsubmit={onSubmit}>
+ <label for="login">Nom d'utilisateur</label>
+ <input type="text" id="login" name="login" placeholder="lirili.larila" required />
+ <label for="password">Mot de passe</label>
+ <input type="password" id="password" name="password" placeholder="Mot de passe" required />
+ <button class="btn" type="submit" disabled={isConnecting}>Connexion</button>
+ </form>
+ </div>
+</div>
+<button id="fab" class="btn" onclick={createDebugUsers}
+ ><img src="/icons/debug.svg" width="100%" alt="+" /></button
+>
+
+<style>
+ .card {
+ width: auto;
+ }
+
+ .bg {
+ background-image: url('/img/header-bg.jpg');
+ height: 100vh;
+ background-size: cover;
+ background-position: center;
+ position: relative;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ h1 {
+ color: var(--text-lime);
+ font-size: 36px;
+ text-align: center;
+ margin: 0;
+ font-weight: 600;
+ }
+
+ form {
+ display: flex;
+ flex-direction: column;
+ color: white;
+ gap: 8px;
+ min-width: 360px;
+ }
+
+ #fab {
+ position: fixed;
+ bottom: 20px;
+ right: 20px;
+ z-index: 1000;
+ border-radius: 50%;
+ width: 56px;
+ height: 56px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-weight: bolder;
+ font-size: 32px;
+ }
+
+ #fab img {
+ transform: scale(2);
+ }
+</style>
diff --git a/ping/frontend/src/routes/stocksapi/chart/+server.ts b/ping/frontend/src/routes/stocksapi/chart/+server.ts
new file mode 100644
index 0000000..3271e83
--- /dev/null
+++ b/ping/frontend/src/routes/stocksapi/chart/+server.ts
@@ -0,0 +1,21 @@
+import type { RequestHandler } from '@sveltejs/kit';
+import yahooFinance from 'yahoo-finance2';
+
+/**
+ * Example request : GET /stocksapi/chart?query=AAPL&startDate=2025-01-01&
+ */
+export const GET: RequestHandler = async ({ request }) => {
+ const sp = new URL(request.url).searchParams;
+ const query = sp.get('query') || 'AAPL';
+ const startDate = sp.get('startDate') || '2025-01-01';
+ const endDate = sp.get('endDate') || new Date().toISOString().split('T')[0];
+ const interval = sp.get('interval') || '1d';
+
+ const data = await yahooFinance.chart(query, { period1: startDate, period2: endDate, interval: interval });
+ return new Response(JSON.stringify(data), {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache',
+ },
+ });
+}; \ No newline at end of file
diff --git a/ping/frontend/src/routes/stocksapi/insights/+server.ts b/ping/frontend/src/routes/stocksapi/insights/+server.ts
new file mode 100644
index 0000000..6be76e9
--- /dev/null
+++ b/ping/frontend/src/routes/stocksapi/insights/+server.ts
@@ -0,0 +1,19 @@
+import type { RequestHandler } from '@sveltejs/kit';
+import yahooFinance from 'yahoo-finance2';
+
+/**
+ * Example request : GET /stocksapi/insights?query=AAPL
+ */
+export const GET: RequestHandler = async ({ request }) => {
+ const sp = new URL(request.url).searchParams;
+ const query = sp.get('query') || 'AAPL';
+
+ const queryOptions = { lang: 'en-US', reportsCount: 2, region: 'US' };
+ const data = await yahooFinance.insights(query, queryOptions);
+ return new Response(JSON.stringify(data), {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache',
+ },
+ });
+}; \ No newline at end of file
diff --git a/ping/frontend/src/routes/stocksapi/quote/+server.ts b/ping/frontend/src/routes/stocksapi/quote/+server.ts
new file mode 100644
index 0000000..96619fc
--- /dev/null
+++ b/ping/frontend/src/routes/stocksapi/quote/+server.ts
@@ -0,0 +1,18 @@
+import type { RequestHandler } from '@sveltejs/kit';
+import yahooFinance from 'yahoo-finance2';
+
+/**
+ * Example request : GET /stocksapi/quote?query=AAPL
+ */
+export const GET: RequestHandler = async ({ request }) => {
+ const sp = new URL(request.url).searchParams;
+ const query = sp.get('query') || 'AAPL';
+
+ const data = await yahooFinance.quote(query);
+ return new Response(JSON.stringify(data), {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache',
+ },
+ });
+}; \ No newline at end of file
diff --git a/ping/frontend/src/routes/stocksapi/search/+server.ts b/ping/frontend/src/routes/stocksapi/search/+server.ts
new file mode 100644
index 0000000..e58fc6b
--- /dev/null
+++ b/ping/frontend/src/routes/stocksapi/search/+server.ts
@@ -0,0 +1,18 @@
+import type { RequestHandler } from '@sveltejs/kit';
+import yahooFinance from 'yahoo-finance2';
+
+/**
+ * Example request : GET /stocksapi/search?query=AAPL
+ */
+export const GET: RequestHandler = async ({ request }) => {
+ const sp = new URL(request.url).searchParams;
+ const query = sp.get('query') || 'AAPL';
+
+ const data = await yahooFinance.search(query, { region: 'US' })
+ return new Response(JSON.stringify(data), {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache',
+ },
+ });
+}; \ No newline at end of file
diff --git a/ping/frontend/src/routes/stocksapi/trendingSymbols/+server.ts b/ping/frontend/src/routes/stocksapi/trendingSymbols/+server.ts
new file mode 100644
index 0000000..3dac574
--- /dev/null
+++ b/ping/frontend/src/routes/stocksapi/trendingSymbols/+server.ts
@@ -0,0 +1,16 @@
+import type { RequestHandler } from '@sveltejs/kit';
+import yahooFinance from 'yahoo-finance2';
+
+/**
+ * Example request : GET /stocksapi/trendingSymbols
+ */
+export const GET: RequestHandler = async () => {
+ const queryOptions = { count: 5, lang: 'en-US' };
+ const data = await yahooFinance.trendingSymbols('US', queryOptions);
+ return new Response(JSON.stringify(data), {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache',
+ },
+ });
+}; \ No newline at end of file
diff --git a/ping/frontend/static/favicon.png b/ping/frontend/static/favicon.png
new file mode 100644
index 0000000..83e6bff
--- /dev/null
+++ b/ping/frontend/static/favicon.png
Binary files differ
diff --git a/ping/frontend/static/icons/ICI b/ping/frontend/static/icons/ICI
new file mode 100644
index 0000000..01a9115
--- /dev/null
+++ b/ping/frontend/static/icons/ICI
@@ -0,0 +1,2 @@
+todo : remove this file
+fact: les triangles sont pas exactement les memes
diff --git a/ping/frontend/static/icons/add-green.svg b/ping/frontend/static/icons/add-green.svg
new file mode 100644
index 0000000..d165f30
--- /dev/null
+++ b/ping/frontend/static/icons/add-green.svg
@@ -0,0 +1,7 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <g id="SVGRepo_bgCarrier" stroke-width="0"/>
+ <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
+ <g id="SVGRepo_iconCarrier"> <path d="M11 8C11 7.44772 11.4477 7 12 7C12.5523 7 13 7.44772 13 8V11H16C16.5523 11 17 11.4477 17 12C17 12.5523 16.5523 13 16 13H13V16C13 16.5523 12.5523 17 12 17C11.4477 17 11 16.5523 11 16V13H8C7.44771 13 7 12.5523 7 12C7 11.4477 7.44772 11 8 11H11V8Z" fill="#00ff77"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12ZM3.00683 12C3.00683 16.9668 7.03321 20.9932 12 20.9932C16.9668 20.9932 20.9932 16.9668 20.9932 12C20.9932 7.03321 16.9668 3.00683 12 3.00683C7.03321 3.00683 3.00683 7.03321 3.00683 12Z" fill="#00ff77"/> </g>
+ </svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/bell.svg b/ping/frontend/static/icons/bell.svg
new file mode 100644
index 0000000..797220a
--- /dev/null
+++ b/ping/frontend/static/icons/bell.svg
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 611.999 611.999" xml:space="preserve">
+<g>
+ <g>
+ <g>
+ <path d="M570.107,500.254c-65.037-29.371-67.511-155.441-67.559-158.622v-84.578c0-81.402-49.742-151.399-120.427-181.203
+ C381.969,34,347.883,0,306.001,0c-41.883,0-75.968,34.002-76.121,75.849c-70.682,29.804-120.425,99.801-120.425,181.203v84.578
+ c-0.046,3.181-2.522,129.251-67.561,158.622c-7.409,3.347-11.481,11.412-9.768,19.36c1.711,7.949,8.74,13.626,16.871,13.626
+ h164.88c3.38,18.594,12.172,35.892,25.619,49.903c17.86,18.608,41.479,28.856,66.502,28.856
+ c25.025,0,48.644-10.248,66.502-28.856c13.449-14.012,22.241-31.311,25.619-49.903h164.88c8.131,0,15.159-5.676,16.872-13.626
+ C581.586,511.664,577.516,503.6,570.107,500.254z M484.434,439.859c6.837,20.728,16.518,41.544,30.246,58.866H97.32
+ c13.726-17.32,23.407-38.135,30.244-58.866H484.434z M306.001,34.515c18.945,0,34.963,12.73,39.975,30.082
+ c-12.912-2.678-26.282-4.09-39.975-4.09s-27.063,1.411-39.975,4.09C271.039,47.246,287.057,34.515,306.001,34.515z
+ M143.97,341.736v-84.685c0-89.343,72.686-162.029,162.031-162.029s162.031,72.686,162.031,162.029v84.826
+ c0.023,2.596,0.427,29.879,7.303,63.465H136.663C143.543,371.724,143.949,344.393,143.97,341.736z M306.001,577.485
+ c-26.341,0-49.33-18.992-56.709-44.246h113.416C355.329,558.493,332.344,577.485,306.001,577.485z"/>
+ <path d="M306.001,119.235c-74.25,0-134.657,60.405-134.657,134.654c0,9.531,7.727,17.258,17.258,17.258
+ c9.531,0,17.258-7.727,17.258-17.258c0-55.217,44.923-100.139,100.142-100.139c9.531,0,17.258-7.727,17.258-17.258
+ C323.259,126.96,315.532,119.235,306.001,119.235z"/>
+ </g>
+ </g>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/closed-wallet.svg b/ping/frontend/static/icons/closed-wallet.svg
new file mode 100644
index 0000000..ffd10f6
--- /dev/null
+++ b/ping/frontend/static/icons/closed-wallet.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 405.867 405.867" xml:space="preserve">
+<g>
+ <path d="M389.887,0H58.973C26.996,0,0.98,26.016,0.98,57.993v287.823c0,33.112,26.938,60.051,60.051,60.051h328.855
+ c8.284,0,15-6.716,15-15V15C404.887,6.716,398.171,0,389.887,0z M58.973,30h315.914v55.985h-23.314V57.993c0-5.523-4.478-10-10-10
+ H32.834C36.869,37.483,47.061,30,58.973,30z M331.572,85.985h-272.6c-11.912,0-22.104-7.483-26.139-17.992h298.738V85.985z
+ M61.031,375.867c-16.57,0-30.051-13.481-30.051-30.051V108.761c8.305,4.598,17.846,7.224,27.992,7.224h315.914v74.778h-63.772
+ c-30.417,0-55.163,24.746-55.163,55.163s24.746,55.163,55.163,55.163h63.772v74.778H61.031z M374.887,281.089h-63.772
+ c-19.389,0-35.163-15.774-35.163-35.163c0-19.389,15.774-35.163,35.163-35.163h63.772V281.089z"/>
+ <path d="M297.166,245.922c0,3.95,1.601,7.82,4.391,10.61s6.66,4.39,10.609,4.39c3.95,0,7.811-1.6,10.601-4.39
+ c2.8-2.79,4.399-6.66,4.399-10.61c0-3.95-1.6-7.81-4.399-10.6c-2.79-2.8-6.65-4.4-10.601-4.4c-3.949,0-7.819,1.6-10.609,4.4
+ C298.767,238.112,297.166,241.982,297.166,245.922z"/>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/coin.svg b/ping/frontend/static/icons/coin.svg
new file mode 100644
index 0000000..331f0aa
--- /dev/null
+++ b/ping/frontend/static/icons/coin.svg
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 512 512">
+ <g>
+ <g>
+ <path d="m256,11c-135.1,0-245,109.9-245,245s109.9,245 245,245c135.1,0 245-109.9 245-245s-109.9-245-245-245zm0,449.2c-112.6,0-204.2-91.6-204.2-204.2 0-112.6 91.6-204.2 204.2-204.2 112.6,0 204.2,91.6 204.2,204.2 0,112.6-91.6,204.2-204.2,204.2z"/>
+ <path d="m268.8,224.8v-66.5c11,4.8 17.8,13.8 20.4,27.2l43-5.6c-2.9-17-9.8-30.6-20.4-40.7-10.7-10.2-25-16.3-43-18.5v-16.8h-24.7v16.8c-19.5,1.9-35.1,9.2-46.9,21.9-11.7,12.6-17.6,28.3-17.6,46.9 0,18.4 5.2,34 15.6,46.9 10.4,12.9 26.7,22.5 48.9,28.8v71.3c-6.1-2.9-11.7-7.7-16.7-14.3-5-6.6-8.4-14.4-10.2-23.5l-44.4,4.8c3.4,22.3 11.2,39.6 23.5,51.9s28.2,19.6 47.8,21.9v31h24.7v-31.8c22.1-3.2 39.4-11.8 51.8-25.9 12.4-14.1 18.6-31.4 18.6-51.9 0-18.4-4.9-33.4-14.8-45.2-9.9-11.8-28.4-21.3-55.6-28.7zm-24.7-8.2c-36.1-11.8-24.2-58.9 0-58.9v58.9zm24.7,122.2v-66.4c36.2,7 33.1,59.5 0,66.4z"/>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/credit-card.svg b/ping/frontend/static/icons/credit-card.svg
new file mode 100644
index 0000000..d84911c
--- /dev/null
+++ b/ping/frontend/static/icons/credit-card.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.5 10.5H20.5M4.5 9.5H20.5M4.5 11.5H20.5M7 15.5H14M5.5 18.5H19.5C20.0523 18.5 20.5 18.0523 20.5 17.5V7.5C20.5 6.94772 20.0523 6.5 19.5 6.5H5.5C4.94772 6.5 4.5 6.94772 4.5 7.5V17.5C4.5 18.0523 4.94772 18.5 5.5 18.5Z" stroke="#ffffff" stroke-width="1.2"/>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/dashboard.svg b/ping/frontend/static/icons/dashboard.svg
new file mode 100644
index 0000000..072ca90
--- /dev/null
+++ b/ping/frontend/static/icons/dashboard.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.2929 4.29289C14 4.58579 14 5.05719 14 6C14 6.94281 14 7.41421 14.2929 7.70711C14.5858 8 15.0572 8 16 8H18C18.9428 8 19.4142 8 19.7071 7.70711C20 7.41421 20 6.94281 20 6C20 5.05719 20 4.58579 19.7071 4.29289C19.4142 4 18.9428 4 18 4H16C15.0572 4 14.5858 4 14.2929 4.29289ZM4.29289 16.2929C4 16.5858 4 17.0572 4 18C4 18.9428 4 19.4142 4.29289 19.7071C4.58579 20 5.05719 20 6 20H8C8.94281 20 9.41421 20 9.70711 19.7071C10 19.4142 10 18.9428 10 18C10 17.0572 10 16.5858 9.70711 16.2929C9.41421 16 8.94281 16 8 16H6C5.05719 16 4.58579 16 4.29289 16.2929ZM14 14C14 13.0572 14 12.5858 14.2929 12.2929C14.5858 12 15.0572 12 16 12H18C18.9428 12 19.4142 12 19.7071 12.2929C20 12.5858 20 13.0572 20 14V18C20 18.9428 20 19.4142 19.7071 19.7071C19.4142 20 18.9428 20 18 20H16C15.0572 20 14.5858 20 14.2929 19.7071C14 19.4142 14 18.9428 14 18V14ZM4.29289 4.29289C4 4.58579 4 5.05719 4 6V10C4 10.9428 4 11.4142 4.29289 11.7071C4.58579 12 5.05719 12 6 12H8C8.94281 12 9.41421 12 9.70711 11.7071C10 11.4142 10 10.9428 10 10V6C10 5.05719 10 4.58579 9.70711 4.29289C9.41421 4 8.94281 4 8 4H6C5.05719 4 4.58579 4 4.29289 4.29289Z" fill="#ffffff"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.82324 4.82324L4.82567 4.82187C4.8276 4.82086 4.83092 4.81924 4.83596 4.81717C4.85774 4.80821 4.90611 4.79291 5.00266 4.77993C5.21339 4.7516 5.50739 4.75001 6 4.75001H8C8.49261 4.75001 8.78661 4.7516 8.99734 4.77993C9.09389 4.79291 9.14225 4.80821 9.16403 4.81717C9.16908 4.81924 9.17239 4.82086 9.17433 4.82187L9.17676 4.82324L9.17814 4.82568C9.17915 4.82761 9.18077 4.83093 9.18284 4.83597C9.1918 4.85775 9.20709 4.90611 9.22008 5.00267C9.24841 5.21339 9.25 5.5074 9.25 6.00001V10C9.25 10.4926 9.24841 10.7866 9.22008 10.9973C9.20709 11.0939 9.1918 11.1423 9.18284 11.164C9.18077 11.1691 9.17915 11.1724 9.17814 11.1743L9.17676 11.1768L9.17433 11.1781C9.17239 11.1792 9.16908 11.1808 9.16403 11.1828C9.14225 11.1918 9.09389 11.2071 8.99734 11.2201C8.78661 11.2484 8.49261 11.25 8 11.25H6C5.50739 11.25 5.21339 11.2484 5.00266 11.2201C4.90611 11.2071 4.85774 11.1918 4.83596 11.1828C4.83092 11.1808 4.8276 11.1792 4.82567 11.1781L4.82324 11.1768L4.82186 11.1743C4.82085 11.1724 4.81923 11.1691 4.81716 11.164C4.8082 11.1423 4.79291 11.0939 4.77992 10.9973C4.75159 10.7866 4.75 10.4926 4.75 10V6.00001C4.75 5.5074 4.75159 5.21339 4.77992 5.00267C4.79291 4.90611 4.8082 4.85775 4.81716 4.83597C4.81923 4.83093 4.82085 4.82761 4.82186 4.82568L4.82324 4.82324ZM5.95525 3.25C5.97013 3.25001 5.98504 3.25001 6 3.25001H8C8.01496 3.25001 8.02987 3.25001 8.04475 3.25C8.47756 3.24995 8.8744 3.24991 9.19721 3.29331C9.55269 3.3411 9.92841 3.45355 10.2374 3.76257C10.5465 4.07159 10.6589 4.44732 10.7067 4.8028C10.7501 5.12561 10.7501 5.52245 10.75 5.95526C10.75 5.97014 10.75 5.98505 10.75 6.00001V10C10.75 10.015 10.75 10.0299 10.75 10.0448C10.7501 10.4776 10.7501 10.8744 10.7067 11.1972C10.6589 11.5527 10.5465 11.9284 10.2374 12.2374C9.92841 12.5465 9.55269 12.6589 9.19721 12.7067C8.87439 12.7501 8.47756 12.7501 8.04474 12.75C8.02987 12.75 8.01496 12.75 8 12.75H6C5.98504 12.75 5.97013 12.75 5.95526 12.75C5.52244 12.7501 5.1256 12.7501 4.80279 12.7067C4.44731 12.6589 4.07159 12.5465 3.76256 12.2374C3.45354 11.9284 3.34109 11.5527 3.2933 11.1972C3.2499 10.8744 3.24994 10.4776 3.25 10.0448C3.25 10.0299 3.25 10.015 3.25 10V6.00001C3.25 5.98505 3.25 5.97013 3.25 5.95526C3.24994 5.52244 3.2499 5.12561 3.2933 4.8028C3.34109 4.44732 3.45354 4.07159 3.76256 3.76257C4.07159 3.45355 4.44731 3.3411 4.80279 3.29331C5.1256 3.24991 5.52243 3.24995 5.95525 3.25ZM14.8257 4.82187L14.8232 4.82324L14.8219 4.82568C14.8209 4.82761 14.8192 4.83093 14.8172 4.83597C14.8082 4.85775 14.7929 4.90611 14.7799 5.00267C14.7516 5.21339 14.75 5.5074 14.75 6.00001C14.75 6.49261 14.7516 6.78662 14.7799 6.99734C14.7929 7.0939 14.8082 7.14226 14.8172 7.16404C14.818 7.16606 14.8194 7.1693 14.8194 7.1693C14.8204 7.17152 14.8219 7.17434 14.8219 7.17434L14.8232 7.17677L14.8257 7.17815C14.8276 7.17916 14.8309 7.18077 14.836 7.18285C14.8577 7.19181 14.9061 7.2071 15.0027 7.22008C15.2134 7.24841 15.5074 7.25001 16 7.25001H18C18.4926 7.25001 18.7866 7.24841 18.9973 7.22008C19.0939 7.2071 19.1423 7.19181 19.164 7.18285C19.1691 7.18077 19.1724 7.17916 19.1743 7.17815L19.1768 7.17677L19.1781 7.17434C19.1791 7.1724 19.1808 7.16909 19.1828 7.16404C19.1918 7.14226 19.2071 7.0939 19.2201 6.99734C19.2484 6.78662 19.25 6.49261 19.25 6.00001C19.25 5.5074 19.2484 5.21339 19.2201 5.00267C19.2071 4.90611 19.1918 4.85775 19.1828 4.83597C19.1808 4.83093 19.1791 4.82761 19.1781 4.82568L19.1768 4.82324L19.1743 4.82187C19.1724 4.82086 19.1691 4.81924 19.164 4.81717C19.1423 4.80821 19.0939 4.79291 18.9973 4.77993C18.7866 4.7516 18.4926 4.75001 18 4.75001H16C15.5074 4.75001 15.2134 4.7516 15.0027 4.77993C14.9061 4.79291 14.8577 4.80821 14.836 4.81717C14.8309 4.81924 14.8276 4.82086 14.8257 4.82187ZM15.9553 3.25H18.0447C18.4776 3.24995 18.8744 3.24991 19.1972 3.29331C19.5527 3.3411 19.9284 3.45355 20.2374 3.76257C20.5465 4.07159 20.6589 4.44732 20.7067 4.8028C20.7501 5.12561 20.7501 5.52244 20.75 5.95526V6.04475C20.7501 6.47757 20.7501 6.8744 20.7067 7.19721C20.6589 7.5527 20.5465 7.92842 20.2374 8.23744C19.9284 8.54647 19.5527 8.65891 19.1972 8.70671C18.8744 8.75011 18.4776 8.75006 18.0447 8.75001H15.9553C15.5224 8.75006 15.1256 8.75011 14.8028 8.70671C14.4473 8.65891 14.0716 8.54647 13.7626 8.23744C13.4535 7.92842 13.3411 7.5527 13.2933 7.19721C13.2499 6.8744 13.2499 6.47757 13.25 6.04475C13.25 6.02988 13.25 6.01496 13.25 6.00001C13.25 5.98505 13.25 5.97014 13.25 5.95526C13.2499 5.52245 13.2499 5.12561 13.2933 4.8028C13.3411 4.44732 13.4535 4.07159 13.7626 3.76257C14.0716 3.45355 14.4473 3.3411 14.8028 3.29331C15.1256 3.24991 15.5224 3.24995 15.9553 3.25ZM15.9553 11.25H18.0447C18.4776 11.25 18.8744 11.2499 19.1972 11.2933C19.5527 11.3411 19.9284 11.4535 20.2374 11.7626C20.5465 12.0716 20.6589 12.4473 20.7067 12.8028C20.7501 13.1256 20.7501 13.5224 20.75 13.9553V18.0448C20.7501 18.4776 20.7501 18.8744 20.7067 19.1972C20.6589 19.5527 20.5465 19.9284 20.2374 20.2374C19.9284 20.5465 19.5527 20.6589 19.1972 20.7067C18.8744 20.7501 18.4776 20.7501 18.0447 20.75H15.9553C15.5224 20.7501 15.1256 20.7501 14.8028 20.7067C14.4473 20.6589 14.0716 20.5465 13.7626 20.2374C13.4535 19.9284 13.3411 19.5527 13.2933 19.1972C13.2499 18.8744 13.2499 18.4776 13.25 18.0448L13.25 14C13.25 13.9851 13.25 13.9701 13.25 13.9553C13.2499 13.5224 13.2499 13.1256 13.2933 12.8028C13.3411 12.4473 13.4535 12.0716 13.7626 11.7626C14.0716 11.4535 14.4473 11.3411 14.8028 11.2933C15.1256 11.2499 15.5224 11.25 15.9553 11.25ZM14.8257 12.8219L14.8232 12.8232L14.8219 12.8257C14.8209 12.8276 14.8192 12.8309 14.8172 12.836C14.8082 12.8578 14.7929 12.9061 14.7799 13.0027C14.7516 13.2134 14.75 13.5074 14.75 14V18C14.75 18.4926 14.7516 18.7866 14.7799 18.9973C14.7929 19.0939 14.8082 19.1423 14.8172 19.164C14.8192 19.1691 14.8209 19.1724 14.8219 19.1743L14.8232 19.1768L14.8257 19.1781C14.8276 19.1792 14.8309 19.1808 14.836 19.1828C14.8577 19.1918 14.9061 19.2071 15.0027 19.2201C15.2134 19.2484 15.5074 19.25 16 19.25H18C18.4926 19.25 18.7866 19.2484 18.9973 19.2201C19.0939 19.2071 19.1423 19.1918 19.164 19.1828C19.1691 19.1808 19.1724 19.1792 19.1743 19.1781L19.1768 19.1768L19.1781 19.1743C19.1791 19.1724 19.1808 19.1691 19.1828 19.164C19.1918 19.1423 19.2071 19.0939 19.2201 18.9973C19.2484 18.7866 19.25 18.4926 19.25 18V14C19.25 13.5074 19.2484 13.2134 19.2201 13.0027C19.2071 12.9061 19.1918 12.8578 19.1828 12.836C19.1816 12.833 19.1805 12.8306 19.1797 12.8287L19.1781 12.8257L19.1768 12.8232L19.1743 12.8219C19.1724 12.8209 19.1691 12.8192 19.164 12.8172C19.1423 12.8082 19.0939 12.7929 18.9973 12.7799C18.7866 12.7516 18.4926 12.75 18 12.75H16C15.5074 12.75 15.2134 12.7516 15.0027 12.7799C14.9061 12.7929 14.8577 12.8082 14.836 12.8172C14.8309 12.8192 14.8276 12.8209 14.8257 12.8219ZM4.82567 16.8219L4.82324 16.8232L4.82186 16.8257C4.82085 16.8276 4.81923 16.8309 4.81716 16.836C4.8082 16.8578 4.7929 16.9061 4.77992 17.0027C4.75159 17.2134 4.75 17.5074 4.75 18C4.75 18.4926 4.75159 18.7866 4.77992 18.9973C4.7929 19.0939 4.8082 19.1423 4.81716 19.164C4.81923 19.1691 4.82085 19.1724 4.82186 19.1743L4.82324 19.1768L4.82567 19.1781C4.8276 19.1792 4.83092 19.1808 4.83596 19.1828C4.85774 19.1918 4.90611 19.2071 5.00266 19.2201C5.21339 19.2484 5.50739 19.25 6 19.25H8C8.49261 19.25 8.78661 19.2484 8.99734 19.2201C9.09389 19.2071 9.14225 19.1918 9.16403 19.1828C9.16658 19.1818 9.1704 19.1801 9.1704 19.1801L9.17433 19.1781L9.17676 19.1768L9.17814 19.1743L9.1796 19.1714C9.18049 19.1695 9.18158 19.1671 9.18284 19.164C9.1918 19.1423 9.20709 19.0939 9.22008 18.9973C9.24841 18.7866 9.25 18.4926 9.25 18C9.25 17.5074 9.24841 17.2134 9.22008 17.0027C9.20709 16.9061 9.1918 16.8578 9.18284 16.836C9.18077 16.8309 9.17915 16.8276 9.17814 16.8257L9.17676 16.8232L9.17433 16.8219C9.17239 16.8209 9.16908 16.8192 9.16403 16.8172C9.14225 16.8082 9.09389 16.7929 8.99734 16.7799C8.78661 16.7516 8.49261 16.75 8 16.75H6C5.50739 16.75 5.21339 16.7516 5.00266 16.7799C4.90611 16.7929 4.85774 16.8082 4.83596 16.8172C4.83092 16.8192 4.8276 16.8209 4.82567 16.8219ZM5.95526 15.25H8.04474C8.47756 15.25 8.87439 15.2499 9.19721 15.2933C9.55269 15.3411 9.92841 15.4535 10.2374 15.7626C10.5465 16.0716 10.6589 16.4473 10.7067 16.8028C10.7501 17.1256 10.7501 17.5224 10.75 17.9553V18.0448C10.7501 18.4776 10.7501 18.8744 10.7067 19.1972C10.6589 19.5527 10.5465 19.9284 10.2374 20.2374C9.92841 20.5465 9.55269 20.6589 9.19721 20.7067C8.87439 20.7501 8.47756 20.7501 8.04474 20.75H5.95525C5.52244 20.7501 5.1256 20.7501 4.80279 20.7067C4.44731 20.6589 4.07159 20.5465 3.76256 20.2374C3.45354 19.9284 3.34109 19.5527 3.2933 19.1972C3.2499 18.8744 3.24994 18.4776 3.25 18.0448V17.9553C3.24994 17.5224 3.2499 17.1256 3.2933 16.8028C3.34109 16.4473 3.45354 16.0716 3.76256 15.7626C4.07159 15.4535 4.44731 15.3411 4.80279 15.2933C5.1256 15.2499 5.52244 15.25 5.95526 15.25Z" fill="#ffffff"/>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/debug.svg b/ping/frontend/static/icons/debug.svg
new file mode 100644
index 0000000..4f6cfb2
--- /dev/null
+++ b/ping/frontend/static/icons/debug.svg
@@ -0,0 +1,7 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <g id="SVGRepo_bgCarrier" stroke-width="0"/>
+ <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
+ <g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M8 9V13.017C8 15.2261 9.79086 17.017 12 17.017C14.2091 17.017 16 15.2261 16 13.017V9H8Z" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> <path d="M9.25 9C9.25 9.41421 9.58579 9.75 10 9.75C10.4142 9.75 10.75 9.41421 10.75 9H9.25ZM13.25 9C13.25 9.41421 13.5858 9.75 14 9.75C14.4142 9.75 14.75 9.41421 14.75 9H13.25ZM12.75 13.017C12.75 12.6028 12.4142 12.267 12 12.267C11.5858 12.267 11.25 12.6028 11.25 13.017H12.75ZM11.25 17.034C11.25 17.4482 11.5858 17.784 12 17.784C12.4142 17.784 12.75 17.4482 12.75 17.034H11.25ZM5 12.267C4.58579 12.267 4.25 12.6028 4.25 13.017C4.25 13.4312 4.58579 13.767 5 13.767V12.267ZM8 13.767C8.41421 13.767 8.75 13.4312 8.75 13.017C8.75 12.6028 8.41421 12.267 8 12.267V13.767ZM6.53205 6.45839C6.2401 6.16455 5.76523 6.16301 5.47139 6.45495C5.17755 6.7469 5.17601 7.22177 5.46795 7.51561L6.53205 6.45839ZM7.46795 9.52861C7.7599 9.82245 8.23477 9.82399 8.52861 9.53205C8.82245 9.2401 8.82399 8.76523 8.53205 8.47139L7.46795 9.52861ZM9.70345 16.3862C9.99572 16.0927 9.99472 15.6178 9.70121 15.3255C9.40769 15.0333 8.93282 15.0343 8.64055 15.3278L9.70345 16.3862ZM6.51955 17.4578C6.22728 17.7513 6.22828 18.2262 6.52179 18.5185C6.81531 18.8107 7.29018 18.8097 7.58245 18.5162L6.51955 17.4578ZM19 13.767C19.4142 13.767 19.75 13.4312 19.75 13.017C19.75 12.6028 19.4142 12.267 19 12.267V13.767ZM16 12.267C15.5858 12.267 15.25 12.6028 15.25 13.017C15.25 13.4312 15.5858 13.767 16 13.767V12.267ZM18.532 7.51561C18.824 7.22177 18.8224 6.7469 18.5286 6.45495C18.2348 6.16301 17.7599 6.16455 17.468 6.45839L18.532 7.51561ZM15.468 8.47139C15.176 8.76523 15.1776 9.2401 15.4714 9.53205C15.7652 9.82399 16.2401 9.82245 16.532 9.52861L15.468 8.47139ZM15.3595 15.3278C15.0672 15.0343 14.5923 15.0333 14.2988 15.3255C14.0053 15.6178 14.0043 16.0927 14.2965 16.3862L15.3595 15.3278ZM16.4175 18.5162C16.7098 18.8097 17.1847 18.8107 17.4782 18.5185C17.7717 18.2262 17.7727 17.7513 17.4805 17.4578L16.4175 18.5162ZM10.75 9V8H9.25V9H10.75ZM10.75 8C10.75 7.30964 11.3096 6.75 12 6.75V5.25C10.4812 5.25 9.25 6.48122 9.25 8H10.75ZM12 6.75C12.6904 6.75 13.25 7.30964 13.25 8H14.75C14.75 6.48122 13.5188 5.25 12 5.25V6.75ZM13.25 8V9H14.75V8H13.25ZM11.25 13.017V17.034H12.75V13.017H11.25ZM5 13.767H8V12.267H5V13.767ZM5.46795 7.51561L7.46795 9.52861L8.53205 8.47139L6.53205 6.45839L5.46795 7.51561ZM8.64055 15.3278L6.51955 17.4578L7.58245 18.5162L9.70345 16.3862L8.64055 15.3278ZM19 12.267H16V13.767H19V12.267ZM17.468 6.45839L15.468 8.47139L16.532 9.52861L18.532 7.51561L17.468 6.45839ZM14.2965 16.3862L16.4175 18.5162L17.4805 17.4578L15.3595 15.3278L14.2965 16.3862Z" fill="#ffffff"/> </g>
+ </svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/edit-pen.svg b/ping/frontend/static/icons/edit-pen.svg
new file mode 100644
index 0000000..0c6f108
--- /dev/null
+++ b/ping/frontend/static/icons/edit-pen.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" id="_24x24_On_Light_Edit" data-name="24x24/On Light/Edit" xmlns="http://www.w3.org/2000/svg">
+ <rect id="view-box" width="24" height="24" fill="none"/>
+ <path id="Shape" d="M.75,17.5A.751.751,0,0,1,0,16.75V12.569a.755.755,0,0,1,.22-.53L11.461.8a2.72,2.72,0,0,1,3.848,0L16.7,2.191a2.72,2.72,0,0,1,0,3.848L5.462,17.28a.747.747,0,0,1-.531.22ZM1.5,12.879V16h3.12l7.91-7.91L9.41,4.97ZM13.591,7.03l2.051-2.051a1.223,1.223,0,0,0,0-1.727L14.249,1.858a1.222,1.222,0,0,0-1.727,0L10.47,3.91Z" transform="translate(3.25 3.25)" fill="#ffffff"/>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/floppy-disk.svg b/ping/frontend/static/icons/floppy-disk.svg
new file mode 100644
index 0000000..4952daf
--- /dev/null
+++ b/ping/frontend/static/icons/floppy-disk.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<g id="Floppy-disk">
+ <path d="M35.2673988,6.0411h-7.9999981v10h7.9999981V6.0411z M33.3697014,14.1434002h-4.2046013V7.9387999h4.2046013V14.1434002z"
+ />
+ <path d="M41,47.0410995H21c-0.5527992,0-1,0.4472008-1,1c0,0.5527,0.4472008,1,1,1h20c0.5527,0,1-0.4473,1-1
+ C42,47.4883003,41.5527,47.0410995,41,47.0410995z"/>
+ <path d="M41,39.0410995H21c-0.5527992,0-1,0.4472008-1,1c0,0.5527,0.4472008,1,1,1h20c0.5527,0,1-0.4473,1-1
+ C42,39.4883003,41.5527,39.0410995,41,39.0410995z"/>
+ <path d="M12,56.0410995h38v-26H12V56.0410995z M14,32.0410995h34v22H14V32.0410995z"/>
+ <path d="M49.3811989,0.0411L49.3610992,0H7C4.7908001,0,3,1.7909,3,4v56c0,2.2092018,1.7908001,4,4,4h50
+ c2.2090988,0,4-1.7907982,4-4V11.6962996L49.3811989,0.0411z M39.9604988,2.0804999v17.9211006H14.0394001V2.0804999H39.9604988z
+ M59,60c0,1.1027985-0.8972015,2-2,2H7c-1.1027999,0-2-0.8972015-2-2V4c0-1.1027999,0.8972001-2,2-2h5v20.0410995h30V2h6.5099983
+ L59,12.5228996V60z"/>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/leaf.svg b/ping/frontend/static/icons/leaf.svg
new file mode 100644
index 0000000..d58987d
--- /dev/null
+++ b/ping/frontend/static/icons/leaf.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 512 512" xml:space="preserve">
+<g>
+ <g>
+ <path d="M499.672,13.221c-1.005-3.461-3.895-6.039-7.451-6.628C253.888-33.118,71.535,114.906,23.355,227.462
+ c-35.724,83.437,22.129,165.159,42.197,189.858c-23.098,45.747-33.31,81.006-33.813,82.74c-1.417,4.973,1.463,10.153,6.436,11.574
+ c0.859,0.247,1.719,0.366,2.578,0.366c4.068,0,7.817-2.683,8.996-6.793c0.226-0.793,9.89-33.723,31.239-76.571
+ c12.847,3.18,49.792,11.226,94.587,11.226c73.157,0,167.241-21.471,211.326-120.656c17.901-40.276,19.245-75.529,20.433-106.632
+ c0.841-21.955,1.627-42.69,8.018-62.854C438.93,75.343,496.344,23.323,496.92,22.806
+ C499.608,20.406,500.677,16.676,499.672,13.221z M397.506,144.061c-7.158,22.577-7.99,44.541-8.886,67.8
+ c-1.17,30.851-2.395,62.753-18.833,99.738c-62.625,140.912-239.093,109.357-279.9,99.924
+ c31.683-58.444,83.545-128.747,160.565-162.444c4.745-2.071,6.902-7.593,4.827-12.328c-2.066-4.731-7.597-6.889-12.324-4.823
+ c-79.73,34.878-132.93,106.024-163.529,159.571c-1.452,2.542-2.855,5.06-4.235,7.564c-20.886-28.017-63.373-97.083-34.629-164.232
+ C85.185,130.604,251.457-5.476,470.855,22.377C451.263,43.299,415.589,87.008,397.506,144.061z"/>
+ </g>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/magnifying_glass_icon.svg b/ping/frontend/static/icons/magnifying_glass_icon.svg
new file mode 100644
index 0000000..dd521f6
--- /dev/null
+++ b/ping/frontend/static/icons/magnifying_glass_icon.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="490" height="490">
+<path fill="none" stroke="#fff" stroke-width="36" stroke-linecap="round"
+d="m280,278a153,153 0 1,0-2,2l170,170m-91-117 110,110-26,26-110-110"/>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/money-bills.svg b/ping/frontend/static/icons/money-bills.svg
new file mode 100644
index 0000000..57b37a7
--- /dev/null
+++ b/ping/frontend/static/icons/money-bills.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 193 193" xml:space="preserve">
+<path style="fill:#ffffff;" d="M150.14,138.849c-0.006,0-0.011,0-0.017,0H2.5c-1.381,0-2.5-1.119-2.5-2.5V93.934
+ c0-0.066,0.001-0.133,0.006-0.199c0.033-0.487,0.207-0.937,0.479-1.308c0.104-0.143,0.226-0.275,0.361-0.395
+ c0.002-0.002,0.002-0.002,0.004-0.004c0.037-0.032,0.074-0.063,0.112-0.093l46.904-37.241c0.442-0.351,0.99-0.542,1.555-0.542
+ h141.067c0.12-0.006,0.223,0.007,0.333,0.021l0,0c0.005,0,0.009,0.002,0.012,0.002h0.001c0.305,0.041,0.596,0.138,0.86,0.281
+ c0.001,0.001,0.002,0.001,0.003,0.002c0,0,0,0,0.001,0c0.215,0.118,0.41,0.265,0.578,0.435c0.187,0.189,0.345,0.409,0.466,0.654
+ c0.093,0.189,0.163,0.391,0.206,0.6c0,0.001,0,0.002,0,0.002c0,0.001,0,0.002,0,0.003c0.036,0.173,0.052,0.349,0.051,0.522v11.452
+ c0,0.005,0,0.01,0,0.014v10.562c0,0.005,0,0.01,0,0.014v10.667c0,0.005,0,0.01,0,0.014v9.777c0,0.698-0.292,1.365-0.806,1.839
+ l-40.359,37.176c-0.002,0.002-0.005,0.004-0.007,0.007h0c-0.003,0.003-0.006,0.002-0.008,0.008c0,0-0.001,0-0.001,0.001
+ c-0.42,0.38-0.969,0.619-1.574,0.644C150.209,138.848,150.175,138.849,150.14,138.849z M102.76,133.849h44.88v-5.358h-44.88V133.849
+ z M53.839,133.849H97.76V96.408H53.839V133.849z M5,133.849h43.839v-5.358H5V133.849z M152.641,127.739v2.908L188,98.077V95.1
+ L152.641,127.739z M102.76,123.491h44.88v-6.138h-44.88V123.491z M5,123.491h43.839v-6.138H5V123.491z M152.641,117.058v3.876
+ L188,88.295v-3.876L152.641,117.058z M102.76,112.353h44.88v-5.699h-44.88V112.353z M5,112.353h43.839v-5.699H5V112.353z
+ M152.641,106.483v3.771L188,77.615v-3.771L152.641,106.483z M102.76,101.654h44.88v-5.246h-44.88V101.654z M5,101.654h43.839
+ v-5.246H5V101.654z M152.641,95.002v4.676L188,67.039v-4.677L152.641,95.002z M106.641,91.408h42.522l34.943-32.255h-42.625
+ l-4.898,4.535c1.644,0.933,3.282,2.354,3.882,4.455c0.802,2.806-0.452,5.814-3.725,8.944c-7.998,7.646-20.262,8.517-23.922,8.602
+ L106.641,91.408z M58.267,91.408h41.014l10.837-10.033c0.01-0.01,0.02-0.019,0.03-0.028l23.972-22.193H97.133l-9.779,8.115
+ c-0.026,0.022-0.052,0.044-0.079,0.065L58.267,91.408z M9.669,91.408h40.768l8.944-7.423c-1.478-0.889-2.861-2.201-3.31-4.1
+ c-1.055-4.466,3.825-8.195,5.429-9.421c9.792-7.482,20.038-7.773,23.388-7.647l4.416-3.664H50.293L9.669,91.408z M78.2,68.368
+ c-3.893,0.738-8.867,2.403-13.664,6.069c-3.091,2.363-3.706,3.846-3.599,4.299c0.133,0.564,1.406,1.286,2.699,1.718L78.2,68.368z
+ M132.618,67.358l-13.677,12.663c4.493-0.815,10.223-2.608,14.344-6.548c1.721-1.646,2.608-3.123,2.374-3.954
+ C135.418,68.669,133.982,67.847,132.618,67.358z"/>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/msg.svg b/ping/frontend/static/icons/msg.svg
new file mode 100644
index 0000000..6f3930f
--- /dev/null
+++ b/ping/frontend/static/icons/msg.svg
@@ -0,0 +1,7 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <g id="SVGRepo_bgCarrier" stroke-width="0"/>
+ <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
+ <g id="SVGRepo_iconCarrier"> <path d="M18 9V7.2C18 6.0799 18 5.51984 17.782 5.09202C17.5903 4.71569 17.2843 4.40973 16.908 4.21799C16.4802 4 15.9201 4 14.8 4H7.2C6.0799 4 5.51984 4 5.09202 4.21799C4.71569 4.40973 4.40973 4.71569 4.21799 5.09202C4 5.51984 4 6.0799 4 7.2V18L8 16M20 20L17.8062 18.5374C17.5065 18.3377 17.3567 18.2378 17.1946 18.167C17.0507 18.1042 16.9 18.0586 16.7454 18.031C16.5713 18 16.3912 18 16.0311 18H11.2C10.0799 18 9.51984 18 9.09202 17.782C8.71569 17.5903 8.40973 17.2843 8.21799 16.908C8 16.4802 8 15.9201 8 14.8V12.2C8 11.0799 8 10.5198 8.21799 10.092C8.40973 9.71569 8.71569 9.40973 9.09202 9.21799C9.51984 9 10.0799 9 11.2 9H16.8C17.9201 9 18.4802 9 18.908 9.21799C19.2843 9.40973 19.5903 9.71569 19.782 10.092C20 10.5198 20 11.0799 20 12.2V20Z" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g>
+ </svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/people.svg b/ping/frontend/static/icons/people.svg
new file mode 100644
index 0000000..b8ad20a
--- /dev/null
+++ b/ping/frontend/static/icons/people.svg
@@ -0,0 +1,7 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <g id="SVGRepo_bgCarrier" stroke-width="0"/>
+ <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
+ <g id="SVGRepo_iconCarrier"> <path d="M17.5291 7.77C17.4591 7.76 17.3891 7.76 17.3191 7.77C15.7691 7.72 14.5391 6.45 14.5391 4.89C14.5391 3.3 15.8291 2 17.4291 2C19.0191 2 20.3191 3.29 20.3191 4.89C20.3091 6.45 19.0791 7.72 17.5291 7.77Z" fill="#ffffff"/> <path d="M20.7916 14.7004C19.6716 15.4504 18.1016 15.7304 16.6516 15.5404C17.0316 14.7204 17.2316 13.8104 17.2416 12.8504C17.2416 11.8504 17.0216 10.9004 16.6016 10.0704C18.0816 9.8704 19.6516 10.1504 20.7816 10.9004C22.3616 11.9404 22.3616 13.6504 20.7916 14.7004Z" fill="#ffffff"/> <path d="M6.44016 7.77C6.51016 7.76 6.58016 7.76 6.65016 7.77C8.20016 7.72 9.43016 6.45 9.43016 4.89C9.43016 3.29 8.14016 2 6.54016 2C4.95016 2 3.66016 3.29 3.66016 4.89C3.66016 6.45 4.89016 7.72 6.44016 7.77Z" fill="#ffffff"/> <path d="M6.55109 12.8506C6.55109 13.8206 6.76109 14.7406 7.14109 15.5706C5.73109 15.7206 4.26109 15.4206 3.18109 14.7106C1.60109 13.6606 1.60109 11.9506 3.18109 10.9006C4.25109 10.1806 5.76109 9.89059 7.18109 10.0506C6.77109 10.8906 6.55109 11.8406 6.55109 12.8506Z" fill="#ffffff"/> <path d="M12.1208 15.87C12.0408 15.86 11.9508 15.86 11.8608 15.87C10.0208 15.81 8.55078 14.3 8.55078 12.44C8.56078 10.54 10.0908 9 12.0008 9C13.9008 9 15.4408 10.54 15.4408 12.44C15.4308 14.3 13.9708 15.81 12.1208 15.87Z" fill="#ffffff"/> <path d="M8.87078 17.9406C7.36078 18.9506 7.36078 20.6106 8.87078 21.6106C10.5908 22.7606 13.4108 22.7606 15.1308 21.6106C16.6408 20.6006 16.6408 18.9406 15.1308 17.9406C13.4208 16.7906 10.6008 16.7906 8.87078 17.9406Z" fill="#ffffff"/> </g>
+ </svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/settings.svg b/ping/frontend/static/icons/settings.svg
new file mode 100644
index 0000000..25f7ec8
--- /dev/null
+++ b/ping/frontend/static/icons/settings.svg
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 512 512" xml:space="preserve">
+<g>
+ <g>
+ <g>
+ <path d="M256,192c-35.285,0-64,28.715-64,64s28.715,64,64,64s64-28.715,64-64S291.285,192,256,192z"/>
+ <path d="M494.699,212.48l-28.245-5.44c-12.651-2.411-22.571-10.688-27.285-22.635c-4.715-12.011-3.051-24.832,4.587-35.221
+ l17.728-24.192c6.229-8.469,5.312-20.245-2.133-27.669l-38.293-38.293c-7.211-7.232-18.603-8.299-27.029-2.581l-23.829,16.107
+ c-10.624,7.232-23.467,8.405-35.307,3.285c-11.797-5.163-19.712-15.403-21.653-28.139l-4.565-29.611
+ C307.072,7.68,298.112,0,287.573,0h-54.144c-10.219,0-19.008,7.253-20.949,17.301l-7.019,36.48
+ c-2.368,12.352-10.389,22.208-22.016,27.008c-11.627,4.843-24.299,3.541-34.709-3.52l-30.763-20.821
+ c-8.427-5.717-19.776-4.651-27.029,2.581L52.651,97.323c-7.445,7.424-8.363,19.2-2.133,27.669l17.728,24.213
+ c7.637,10.368,9.301,23.189,4.587,35.2c-4.715,11.947-14.635,20.224-27.307,22.635l-28.224,5.44
+ C7.253,214.421,0,223.211,0,233.429v54.144c0,10.539,7.68,19.499,18.091,21.099l29.611,4.565
+ c12.736,1.941,22.976,9.856,28.139,21.653c5.141,11.797,3.947,24.661-3.285,35.328l-16.107,23.808
+ c-5.739,8.448-4.651,19.797,2.581,27.029l38.293,38.293c7.445,7.467,19.2,8.32,27.669,2.133l24.213-17.728
+ c10.368-7.616,23.168-9.259,35.2-4.587c11.947,4.715,20.224,14.635,22.635,27.307l5.44,28.224
+ C214.421,504.747,223.211,512,233.429,512h54.144c10.539,0,19.499-7.68,21.099-18.091l3.2-20.821
+ c2.005-13.035,10.133-23.381,22.293-28.395c12.075-5.035,25.195-3.477,35.84,4.331l17.003,12.459
+ c8.427,6.187,20.224,5.333,27.669-2.133l38.293-38.293c7.232-7.232,8.32-18.581,2.581-27.029l-16.107-23.829
+ c-7.232-10.645-8.427-23.509-3.285-35.307c5.163-11.797,15.403-19.712,28.139-21.653l29.611-4.565
+ c10.411-1.6,18.091-10.56,18.091-21.099v-54.144C512,223.211,504.747,214.421,494.699,212.48z M256,362.667
+ c-58.816,0-106.667-47.851-106.667-106.667S197.184,149.333,256,149.333S362.667,197.184,362.667,256
+ S314.816,362.667,256,362.667z"/>
+ </g>
+ </g>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/side-menu.svg b/ping/frontend/static/icons/side-menu.svg
new file mode 100644
index 0000000..5972d63
--- /dev/null
+++ b/ping/frontend/static/icons/side-menu.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4 18L20 18" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
+<path d="M4 12L20 12" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
+<path d="M4 6L20 6" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/trash.svg b/ping/frontend/static/icons/trash.svg
new file mode 100644
index 0000000..e19d236
--- /dev/null
+++ b/ping/frontend/static/icons/trash.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 512 512" xml:space="preserve">
+<g>
+ <g>
+ <path d="M465.423,48.241h-137.61V23.955C327.813,10.746,317.082,0,303.893,0h-95.785c-13.19,0-23.92,10.746-23.92,23.955V48.24
+ H46.577c-6.655,0-12.049,5.394-12.049,12.049c0,6.655,5.394,12.049,12.049,12.049h22.332l15.228,396.396
+ C85.069,492.995,104.818,512,129.099,512h253.804c24.281,0,44.03-19.006,44.96-43.267l15.228-396.396h22.332
+ c6.653,0,12.049-5.394,12.049-12.049C477.472,53.635,472.078,48.241,465.423,48.241z M208.285,24.097h95.43v24.143h-95.43V24.097z
+ M403.784,467.809c-0.433,11.268-9.605,20.094-20.882,20.094H129.099c-11.276,0-20.448-8.827-20.882-20.095L93.025,72.338h325.952
+ L403.784,467.809z"/>
+ </g>
+</g>
+<g>
+ <g>
+ <path d="M182.63,181.571c-0.127-6.575-5.494-11.817-12.042-11.817c-0.078,0-0.158,0-0.236,0.002
+ c-6.652,0.128-11.943,5.626-11.815,12.278l3.781,196.634c0.126,6.575,5.495,11.817,12.042,11.817c0.078,0,0.158,0,0.236-0.002
+ c6.653-0.128,11.943-5.624,11.815-12.278L182.63,181.571z"/>
+ </g>
+</g>
+<g>
+ <g>
+ <path d="M255.998,169.753c-6.654,0-12.049,5.394-12.049,12.049v196.634c0,6.654,5.394,12.049,12.049,12.049
+ c6.655,0,12.049-5.394,12.049-12.049V181.802C268.047,175.148,262.653,169.753,255.998,169.753z"/>
+ </g>
+</g>
+<g>
+ <g>
+ <path d="M341.645,169.756c-6.628-0.147-12.151,5.162-12.278,11.815l-3.781,196.634c-0.129,6.653,5.162,12.15,11.815,12.278
+ c0.078,0.001,0.158,0.002,0.236,0.002c6.546,0,11.916-5.244,12.042-11.817l3.781-196.634
+ C353.588,175.38,348.299,169.883,341.645,169.756z"/>
+ </g>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/triangle-down.svg b/ping/frontend/static/icons/triangle-down.svg
new file mode 100644
index 0000000..9a40495
--- /dev/null
+++ b/ping/frontend/static/icons/triangle-down.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg fill="#ffffff" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="800px" height="800px" viewBox="0 0 96.154 96.154"
+ xml:space="preserve">
+<g>
+ <path d="M0.561,20.971l45.951,57.605c0.76,0.951,2.367,0.951,3.127,0l45.956-57.609c0.547-0.689,0.709-1.716,0.414-2.61
+ c-0.061-0.187-0.129-0.33-0.186-0.437c-0.351-0.65-1.025-1.056-1.765-1.056H2.093c-0.736,0-1.414,0.405-1.762,1.056
+ c-0.059,0.109-0.127,0.253-0.184,0.426C-0.15,19.251,0.011,20.28,0.561,20.971z"/>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/triangle-up.svg b/ping/frontend/static/icons/triangle-up.svg
new file mode 100644
index 0000000..0b54139
--- /dev/null
+++ b/ping/frontend/static/icons/triangle-up.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg fill="#ffffff" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="800px" height="800px" viewBox="0 0 123.959 123.959"
+ xml:space="preserve">
+<g>
+ <path d="M66.18,29.742c-2.301-2.3-6.101-2.3-8.401,0l-56,56c-3.8,3.801-1.1,10.2,4.2,10.2h112c5.3,0,8-6.399,4.2-10.2L66.18,29.742
+ z"/>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/icons/wallet.svg b/ping/frontend/static/icons/wallet.svg
new file mode 100644
index 0000000..7dfd46f
--- /dev/null
+++ b/ping/frontend/static/icons/wallet.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 76.304 76.304" xml:space="preserve">
+<g>
+ <path d="M72.325,33.234v-2.947c0-5.389-3.698-9.919-8.686-11.217l-0.009-4.859c0-4.742-3.859-8.601-8.603-8.601h-0.455L14.31,18.1
+ c-0.917,0.053-1.787,0.265-2.604,0.584h-0.105C5.205,18.684,0,23.889,0,30.287v28.804c0,6.397,5.204,11.603,11.601,11.603h49.123
+ c6.396,0,11.601-5.205,11.601-11.603V55.26c2.323-0.899,3.979-3.151,3.979-5.789v-10.45C76.303,36.385,74.648,34.133,72.325,33.234
+ z M70.303,49.47c0,0.118-0.093,0.211-0.211,0.211H53.851c-0.118,0-0.21-0.093-0.21-0.211V39.021c0-0.115,0.094-0.209,0.21-0.209
+ h16.241c0.116,0,0.211,0.094,0.211,0.209V49.47z M55.398,11.637c1.261,0.18,2.232,1.266,2.232,2.579l0.008,4.469H32.679
+ L55.398,11.637z M60.724,64.693H11.602c-3.093,0-5.601-2.509-5.601-5.603V30.287c0-3.095,2.508-5.603,5.601-5.603h49.122
+ c3.094,0,5.601,2.508,5.601,5.603v2.525H53.851c-3.424,0-6.21,2.785-6.21,6.209V49.47c0,3.425,2.786,6.211,6.21,6.211h12.474v3.41
+ C66.325,62.184,63.818,64.693,60.724,64.693z"/>
+</g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/img/default-avatar.png b/ping/frontend/static/img/default-avatar.png
new file mode 100644
index 0000000..406d770
--- /dev/null
+++ b/ping/frontend/static/img/default-avatar.png
Binary files differ
diff --git a/ping/frontend/static/img/favicon.svg b/ping/frontend/static/img/favicon.svg
new file mode 100644
index 0000000..3d7b3eb
--- /dev/null
+++ b/ping/frontend/static/img/favicon.svg
@@ -0,0 +1,29 @@
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg623209" version="1.1" viewBox="414 286.5 195 195">
+ <metadata id="metadata623215">
+ <rdf:rdf>
+ <cc:work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ </cc:work>
+ </rdf:rdf>
+ </metadata>
+ <defs id="defs623213"/>
+ <linearGradient spreadMethod="pad" y2="30%" x2="-10%" y1="120%" x1="30%" id="3d_gradient2-logo-9cc91ee9-bcf4-468b-9589-30bc930545e6">
+ <stop id="stop623190" stop-opacity="1" stop-color="#ffffff" offset="0%"/>
+ <stop id="stop623192" stop-opacity="1" stop-color="#000000" offset="100%"/>
+ </linearGradient>
+ <linearGradient gradientTransform="rotate(-30)" spreadMethod="pad" y2="30%" x2="-10%" y1="120%" x1="30%" id="3d_gradient3-logo-9cc91ee9-bcf4-468b-9589-30bc930545e6">
+ <stop id="stop623195" stop-opacity="1" stop-color="#ffffff" offset="0%"/>
+ <stop id="stop623197" stop-opacity="1" stop-color="#cccccc" offset="50%"/>
+ <stop id="stop623199" stop-opacity="1" stop-color="#000000" offset="100%"/>
+ </linearGradient>
+ <g id="logo-group">
+ <image xlink:href="" id="container" style="display: none;" x="272" y="144" width="480" height="480" transform="translate(0 0)"/>
+ <g id="logo-center" transform="translate(0 0)">
+ <image xlink:href="" id="icon_container" style="display: none;" x="0" y="0"/>
+ <g id="slogan" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" transform="translate(0 0)"/>
+ <g id="title" style="font-style:normal;font-weight:400;font-size:72px;line-height:1;font-family:'Brandmark Dots 1 Color';font-variant-ligatures:normal;text-align:center;text-anchor:middle" transform="translate(0 0)"/>
+ <image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAIoUlEQVR4Xu3dzXYTRxCG4TEn1wXsSe4I/Ad3BOxJ7ioblBHYHCWxpJnq6q6vul7W0z3VX9VzxMiyfLPwjwRI4GwCN2RDAiRwPgGAMB0kcCEBgDAeJAAQZoAEbAnwCmLLjVVFEgBIkUZzTFsCALHlxqoiCQCkSKM5pi0BgNhyY1WRBABSpNEc05YAQGy5sapIAgAp0miOaUsAILbcWFUkAYAUaTTHtCUAEFturCqSAECKNJpj2hIAiC03VhVJACBFGs0xbQkAxJYbq4okAJAijeaYtgQAYsuNVUUSAEiRRnNMWwIAseXGqiIJAKRIozmmLQGA2HJjVZEEAFKk0RzTlgBAbLmxqkgCACnSaI5pSwAgttxYVSQBgBRpNMe0JQAQW26sKpIAQIo02uuY94flN6+9MuwDkAxdEqrx3bflIFRO91IA0j3iuW4AkLn6yWmcEwCIc6BsN1cCAJmrn5zGOQGAOAfKdnMlAJC5+slpnBMAiHOgbDdXAgCZq5+cxjkBgDgHynZzJQCQufrJaZwTAIhzoGw3VwIAmaufnMY5AYA4B8p2cyUAkLn6yWmcEwCIc6BsN1cCAJmrn5zGOQGAOAfKdnMlAJC5+slpnBMAiHOgbDdXAgCZq5+cJmECv/+53B8Oy51C6fxOukIXqOFXAko4jkUBhOGUSUANB0BkRoNCFHEAhLmUSEAVB0AkxqN2Eco4AFJ7NsNPr44DIOEjUreADDgAUnc+Q0+eBQdAQsek5s0z4QBIzRkNO3U2HAAJG5V6N86IAyD15jTkxFlxACRkXGrdNDMOgNSa1eGnHY3j5mb5sH4K+KPnQfmwomea7PUrgQgcX94sn7x/XwUgDLV7AlE4jgcBiHs72dAzgUgcAPHsJHu5JxCNAyDuLWVDrwQUcMgAWcM4vlPw9/GhyCtg9smbgAoOCSBHHOtbae9/vEe8vq0GkryD7VH5u7+Wh+X7cuux15Y9rs1c6EP6KY7nw1wreMuhuSZnAmo4Ql9BXsIBkpyD7VG1Io4wIJdwgMRj3HLtoYojBMgWHCDJNeAt1SrjGA5kDw6QtIxdjrXqOIYCseAASY5Bt1SZAccwIC04foX/arn9+tr3k5WWxrKmPYEsOIYAccHx3BOQtE9n8A6ZcHQH4ooDJMGj3X77bDi6AumCAyTtUxq0Q0Yc3YB0xQGSoBG33zYrji5AhuAAiX1aB6/MjKMLkDWQD+uHzR6H9YEH92FR771RdhxdgPzYFCR7Z2m662fA0Q1IBJJXy3L3+e3AV67pRtrvQLPg6AoEJH4Dl2mnmXB0BwKSTKPdXutsOIYAAUn74GXYYTSOZdCbM8N+o3D0gzvPJONYzYqjR4IXvzgOJD0ij90THPvyv/rNiiDZF6jy1X98Wx6/L+vPvUb9G/Tfqp7HuQqEZ5Ke8Y/bGxy2rDcBiUCyflvK/fqVQg+2Y7HqNAFw2OdhMxCQ2EOOXAmOtvR3AQFJW9ijV4OjPfHdQEDSHvqIHcDhk7IJCEh8wu+1Czj8kjUDAYlfEzx3Aodnmuv3T7duN/rnJLy7db5j4Gid5v+vbwbCK4l/Uyw7gsOS2vU1LkCCkDysPye5v37E+a8AR78euwEBSb8mXdoZHH1zdwVyLHVt2O36eZ9hPwFfn0nKvpKAoy+O4+7uQEDSv2lPGfPBwwFRdwECkr6d45Wjb76nu3cDApI+TQRHn1zP7doVCEh8mwkO3zy37NYdCEi2tOH6NeC4nlGPK4YAAUlb68DRll/L6mFAQGJrEzhsuXmtGgoEJPvaBo59efW4ejgQkGxrIzi25dT7qhAgILnc1qF/kmIthe8kO9+PMCAgebkp4Oj9mrBv/1AgIPl3s8Cxb3hHXB0OBCQ/2wyOEeO+/x4SQKojAcf+wR21QgZIBJL16fTx6+vlblTYL90HHJHpX7+3FJBqSMBxfUCjr5ADUgUJOKJHf9v9JYHMjgQc24ZT4SpZILMiAYfC2G+vQRrI09ufd4fDwG8v6fjgDo7tg6lypTyQWZCAQ2Xk99WRAkh2JODYN5RKV6cBEoFk/RDfx89vl9uWhoGjJb34tamAZEMCjvgBb60gHZAsSMDROpoa61MCUUcCDo3h9qgiLRBVJODwGEudPVIDUUMCDp3B9qokPRAVJODwGkmtfaYAEo0EHFpD7VnNNEAikKx/euHT8b7rR2Heezbl0l58wcKopH/eZyogEUhGtgscI9OeFMisSMAxHseUryDPMa7PBWM/Bdyxf+DoGO6Vraf7L9bpeWdAwp+9jsMx9SvIDK8k4IjFUQJI1mcScMTjKAMkGxJwaOAoBSQLEnDo4CgH5AnJ/fqDvdAvizs3AuDQwlESiCoScOjhKAtEDQk4NHGUBqKCBBy6OMoDiUYCDm0cAHnqz/oT9+EP7uDQxwGQkx6NRAKOHDgA8p8+jUACjjw4APJCr3oiAUcuHAA5068eSMCRDwdALvTMEwk4cuIAyJW+eSABR14cANnQuxYk4NgQsPglU/9GoVf2FiTg8Eo/dh+AbMx/DxJwbAw1wWUA2dGkLUjAsSPQBJcCZGeTLiEBx84wE1wOEEOTXkICDkOQCZYAxNikUyTgMIaYYBlAGpp0RLIuP3x5szw0bMNS4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotP4B/zpSHgk1qeLgAAAABJRU5ErkJggg==" id="icon" x="414" y="0" width="195" height="195" transform="translate(0 286.5) "/>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/img/header-bg.jpg b/ping/frontend/static/img/header-bg.jpg
new file mode 100644
index 0000000..ca76595
--- /dev/null
+++ b/ping/frontend/static/img/header-bg.jpg
Binary files differ
diff --git a/ping/frontend/static/img/logo.svg b/ping/frontend/static/img/logo.svg
new file mode 100644
index 0000000..c73d1fe
--- /dev/null
+++ b/ping/frontend/static/img/logo.svg
@@ -0,0 +1,41 @@
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg222447" version="1.1" viewBox="64.45 293.63 895.08 160.43">
+ <metadata id="metadata222453">
+ <rdf:rdf>
+ <cc:work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ </cc:work>
+ </rdf:rdf>
+ </metadata>
+ <defs id="defs222451"/>
+ <linearGradient spreadMethod="pad" y2="30%" x2="-10%" y1="120%" x1="30%" id="3d_gradient2-logo-9cc91ee9-bcf4-468b-9589-30bc930545e6">
+ <stop id="stop222428" stop-opacity="1" stop-color="#ffffff" offset="0%"/>
+ <stop id="stop222430" stop-opacity="1" stop-color="#000000" offset="100%"/>
+ </linearGradient>
+ <linearGradient gradientTransform="rotate(-30)" spreadMethod="pad" y2="30%" x2="-10%" y1="120%" x1="30%" id="3d_gradient3-logo-9cc91ee9-bcf4-468b-9589-30bc930545e6">
+ <stop id="stop222433" stop-opacity="1" stop-color="#ffffff" offset="0%"/>
+ <stop id="stop222435" stop-opacity="1" stop-color="#cccccc" offset="50%"/>
+ <stop id="stop222437" stop-opacity="1" stop-color="#000000" offset="100%"/>
+ </linearGradient>
+ <g id="logo-group">
+ <image xlink:href="" id="container" style="display: none;" x="272" y="144" width="480" height="480" transform="translate(0 0)"/>
+ <g id="logo-center" transform="translate(5.684341886080802e-14 0)">
+ <image xlink:href="" id="icon_container" style="display: none;"/>
+ <g id="slogan" style="font-style:normal;font-weight:400;font-size:32px;line-height:1;font-family:Montserrat;font-variant-ligatures:none;text-align:center;text-anchor:middle" transform="translate(0 0)"/>
+ <g id="title" style="font-style:normal;font-weight:400;font-size:72px;line-height:1;font-family:'Brandmark Dots 1 Color';font-variant-ligatures:normal;text-align:center;text-anchor:middle" transform="translate(0 0)">
+ <g id="path222456" aria-label="P" transform="translate(0 312.40198) translate(66.20587072499995 18.536) scale(1.65) translate(-270.48781 50.4)"> <path class="c1" d="M116.52588,101.7917c-1.36816,2.23242-4.32031,2.95215-6.55273,1.51172 c-2.30469-1.36719-2.95215-4.32031-1.58398-6.55176c0.86426-1.44043,1.44043-3.09668,1.44043-4.6084 c0-1.87207-0.43262-7.77734-6.19336-7.77734H90.24365v36.0752c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.16016-4.75293-4.75293V79.5417c0-2.5918,2.16016-4.75195,4.75293-4.75195h18.2168 c10.80176,0,15.69727,9,15.69727,17.35352C119.3335,95.3835,118.32568,98.83955,116.52588,101.7917z" transform="translate(189.82131 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M99.74854,109.35225c-2.59277,0-4.75293-2.16016-4.75293-4.82422c0-2.5918,2.16016-4.75195,4.75293-4.75195 c2.66406,0,4.75195,2.16016,4.75195,4.75195C104.50049,107.19209,102.4126,109.35225,99.74854,109.35225z" transform="translate(189.82131 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222458" aria-label="A" transform="translate(0 312.40198) translate(127.67317222499996 18.536) scale(1.65) translate(-307.74072 50.4)"> <path class="c1" d="M117.13755,104.6003l-12.81689-27.07422c-0.79199-1.65625-2.52051-2.73633-4.32031-2.73633 c-1.87207,0-3.52832,1.08008-4.32031,2.73633l-19.44189,40.82715c-1.08008,2.37598-0.07178,5.25684,2.3042,6.4082 c2.37598,1.08008,5.18457,0.07227,6.33643-2.30371l4.53662-9.50488h24.19385c1.65625,0,3.09619-0.86426,3.96045-2.16016 C119.22593,108.34444,117.92954,106.25655,117.13755,104.6003z M93.30357,104.74385l6.69678-14.11328l6.76855,14.11328H93.30357z" transform="translate(231.934901 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M124.19419,120.44112c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59229,0-4.75244-2.16016-4.75244-4.75293c0-2.66406,2.16016-4.82422,4.75244-4.82422 C122.03403,115.6169,124.19419,117.77705,124.19419,120.44112z" transform="translate(231.934901 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222460" aria-label="T" transform="translate(0 312.40198) translate(200.92322272499987 18.536) scale(1.65) translate(-352.13469 50.4)"> <path class="c1" d="M104.75244,120.44112c0,2.59277-2.08789,4.75293-4.75293,4.75293 c-2.66406,0-4.75195-2.16016-4.75195-4.75293v-36.0752H84.80615c-2.5918,0-4.75195-2.16016-4.75195-4.82422 c0-2.5918,2.16016-4.75195,4.75195-4.75195h15.19336c2.88086,0,4.75293,2.16016,4.75293,4.75195V120.44112z" transform="translate(272.08049 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M119.9458,79.5417c0,2.66406-2.16016,4.82422-4.75293,4.82422c-2.66406,0-4.82422-2.16016-4.82422-4.82422 c0-2.5918,2.16016-4.75195,4.82422-4.75195C117.78564,74.78975,119.9458,76.94991,119.9458,79.5417z" transform="translate(272.08049 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222462" aria-label="A" transform="translate(0 312.40198) translate(261.55521172499994 18.536) scale(1.65) translate(-388.88135 50.4)"> <path class="c1" d="M117.13755,104.6003l-12.81689-27.07422c-0.79199-1.65625-2.52051-2.73633-4.32031-2.73633 c-1.87207,0-3.52832,1.08008-4.32031,2.73633l-19.44189,40.82715c-1.08008,2.37598-0.07178,5.25684,2.3042,6.4082 c2.37598,1.08008,5.18457,0.07227,6.33643-2.30371l4.53662-9.50488h24.19385c1.65625,0,3.09619-0.86426,3.96045-2.16016 C119.22593,108.34444,117.92954,106.25655,117.13755,104.6003z M93.30357,104.74385l6.69678-14.11328l6.76855,14.11328H93.30357z" transform="translate(313.075531 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M124.19419,120.44112c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59229,0-4.75244-2.16016-4.75244-4.75293c0-2.66406,2.16016-4.82422,4.75244-4.82422 C122.03403,115.6169,124.19419,117.77705,124.19419,120.44112z" transform="translate(313.075531 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222464" aria-label="P" transform="translate(0 312.40198) translate(355.5488477249999 18.536) scale(1.65) translate(-445.84719 50.4)"> <path class="c1" d="M116.52588,101.7917c-1.36816,2.23242-4.32031,2.95215-6.55273,1.51172 c-2.30469-1.36719-2.95215-4.32031-1.58398-6.55176c0.86426-1.44043,1.44043-3.09668,1.44043-4.6084 c0-1.87207-0.43262-7.77734-6.19336-7.77734H90.24365v36.0752c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.16016-4.75293-4.75293V79.5417c0-2.5918,2.16016-4.75195,4.75293-4.75195h18.2168 c10.80176,0,15.69727,9,15.69727,17.35352C119.3335,95.3835,118.32568,98.83955,116.52588,101.7917z" transform="translate(365.18069 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M99.74854,109.35225c-2.59277,0-4.75293-2.16016-4.75293-4.82422c0-2.5918,2.16016-4.75195,4.75293-4.75195 c2.66406,0,4.75195,2.16016,4.75195,4.75195C104.50049,107.19209,102.4126,109.35225,99.74854,109.35225z" transform="translate(365.18069 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222466" aria-label="I" transform="translate(0 312.40198) translate(435.39543322499986 16.39760000000001) scale(1.65) translate(-494.23906 51.696)"> <path class="c3" d="M95.21143,78.2458c0-2.59277,2.16016-4.75293,4.75293-4.75293c2.66406,0,4.82422,2.16016,4.82422,4.75293 c0,2.66406-2.16016,4.82422-4.82422,4.82422C97.37158,83.07002,95.21143,80.90987,95.21143,78.2458z" transform="translate(399.02763 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> <path class="c1" d="M95.21143,120.44112V92.57491c0-2.5918,2.16016-4.75195,4.75293-4.75195 c2.66406,0,4.82422,2.16016,4.82422,4.75195v27.86621c0,2.59277-2.16016,4.75293-4.82422,4.75293 C97.37158,125.19405,95.21143,123.03389,95.21143,120.44112z" transform="translate(399.02763 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> </g>
+ <g id="path222468" aria-label="M" transform="translate(0 312.40198) translate(475.07278522499985 18.550630549999994) scale(1.65) translate(-518.28594 50.391133)"> <path class="c1" d="M117.89355,95.59932l-14.04102,27.14648c-0.86426,1.51172-2.44824,2.44824-4.17676,2.44824 c-1.72754,0-3.31152-0.93652-4.17578-2.52051L82.10645,96.03096v24.41016c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.16016-4.75293-4.75293V79.5417c0-2.16016,1.44043-4.03223,3.60059-4.6084 c2.08789-0.50391,4.32031,0.43262,5.3291,2.37598l18.28906,34.70703l18.79395-34.77832 c1.00781-1.87207,3.24023-2.80859,5.32813-2.30469c2.08789,0.57617,3.60059,2.44824,3.60059,4.6084v26.57031 c0,2.59277-2.16016,4.75293-4.82422,4.75293c-2.59277,0-4.75293-2.16016-4.75293-4.75293V95.59932z" transform="translate(445.75664 -125.18939)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M122.64648,125.19405c-2.59277,0-4.75293-2.16016-4.75293-4.75293 c0-2.66406,2.16016-4.82422,4.75293-4.82422c2.66406,0,4.82422,2.16016,4.82422,4.82422 C127.4707,123.03389,125.31055,125.19405,122.64648,125.19405z" transform="translate(445.75664 -125.18939)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222470" aria-label="V" style="display: none;"> <path class="c1" d="M104.3493,122.38545c-0.71973,1.72852-2.44824,2.87988-4.3916,2.87988 c-1.87207,0-3.60059-1.15137-4.32031-2.87988l-17.8584-40.89941c-1.08008-2.44824,0-5.25684,2.44824-6.26465 c2.37695-1.08008,5.18457,0,6.26465,2.44824l13.53711,31.10645l7.77734-18.00098c1.00781-2.37695,3.81641-3.45703,6.26465-2.44824 c2.37598,1.08008,3.52832,3.8877,2.44824,6.33594L104.3493,122.38545z" transform="translate(505.227103 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M122.63934,79.5417c0,2.66406-2.08789,4.82422-4.75293,4.82422c-2.5918,0-4.75195-2.16016-4.75195-4.82422 c0-2.5918,2.16016-4.75195,4.75195-4.75195C120.55145,74.78975,122.63934,76.94991,122.63934,79.5417z" transform="translate(505.227103 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222472" aria-label="E" transform="translate(0 312.40198) translate(755.8694062749997 18.536) scale(1.65) translate(-636.53469 50.4)"> <path class="c1" d="M87.75879,125.19405c-2.5918,0-4.75195-2.16016-4.75195-4.75293V79.5417 c0-2.5918,2.16016-4.75195,4.75195-4.75195h9.9375c2.5918,0,4.75195,2.16016,4.75195,4.75195 c0,2.66406-2.16016,4.82422-4.75195,4.82422h-5.1123V95.3835h16.70508c2.66406,0,4.75195,1.94434,4.75195,4.6084 c0,2.5918-2.08789,4.53613-4.75195,4.53613H92.58398v11.08887h19.65723c2.66406,0,4.75195,2.16016,4.75195,4.82422 c0,2.59277-2.08789,4.75293-4.75195,4.75293H87.75879z" transform="translate(553.52785 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M112.02539,84.36592c-2.66406,0-4.82422-2.16016-4.82422-4.82422c0-2.5918,2.16016-4.75195,4.82422-4.75195 c2.5918,0,4.75195,2.16016,4.75195,4.75195C116.77734,82.20576,114.61719,84.36592,112.02539,84.36592z" transform="translate(553.52785 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path222474" aria-label="S" transform="translate(0 312.40198) translate(825.0332812749998 16.39760000000001) scale(1.65) translate(-678.45219 51.696)"> <path class="c3" d="M90.67529,115.04073c0,2.66406-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.08887-4.75293-4.75293s2.16016-4.75195,4.75293-4.75195 C88.51514,110.28877,90.67529,112.37666,90.67529,115.04073z" transform="translate(597.35405 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> <path class="c1" d="M102.48486,126.48994c-3.74512,0-8.78516-1.44043-8.78516-5.1123 c0-3.02441,2.01563-4.68066,4.39258-4.53613c2.44824,0.14355,5.1123,1.00781,7.7041-0.2168 c2.0166-0.93555,3.52832-2.73633,3.52832-5.25586c0-3.02441-3.38379-4.96875-10.72852-7.63281 c-6.625-2.37598-16.56152-5.32813-16.63379-15.19336c0-3.74414,1.44043-7.27246,4.10449-10.00879 c2.30469-2.30469,6.55273-5.04102,13.96973-5.04102c8.42383,0,14.04102,4.46484,15.91309,7.12891 c1.2959,1.72852,1.08008,4.03223-0.21582,5.68848c-1.72852,2.16016-4.32031,1.94434-6.12109,0.36035 c-1.2959-1.15234-4.32031-4.17676-9.86426-4.17676c-4.8252,0-8.20898,2.52051-8.20898,6.04883 c0,2.30371,2.52051,4.24805,10.00879,7.12891c9.2168,3.52832,17.35352,7.41602,17.35352,16.27344 C118.90186,119.07295,113.93311,126.48994,102.48486,126.48994z" transform="translate(597.35405 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> </g>
+ <g id="path222476" aria-label="T" transform="translate(0 312.40198) translate(891.9789292749999 18.536) scale(1.65) translate(-719.02531 50.4)"> <path class="c1" d="M104.75244,120.44112c0,2.59277-2.08789,4.75293-4.75293,4.75293 c-2.66406,0-4.75195-2.16016-4.75195-4.75293v-36.0752H84.80615c-2.5918,0-4.75195-2.16016-4.75195-4.82422 c0-2.5918,2.16016-4.75195,4.75195-4.75195h15.19336c2.88086,0,4.75293,2.16016,4.75293,4.75195V120.44112z" transform="translate(638.97111 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M119.9458,79.5417c0,2.66406-2.16016,4.82422-4.75293,4.82422c-2.66406,0-4.82422-2.16016-4.82422-4.82422 c0-2.5918,2.16016-4.75195,4.82422-4.75195C117.78564,74.78975,119.9458,76.94991,119.9458,79.5417z" transform="translate(638.97111 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ </g>
+ <image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAIoUlEQVR4Xu3dzXYTRxCG4TEn1wXsSe4I/Ad3BOxJ7ioblBHYHCWxpJnq6q6vul7W0z3VX9VzxMiyfLPwjwRI4GwCN2RDAiRwPgGAMB0kcCEBgDAeJAAQZoAEbAnwCmLLjVVFEgBIkUZzTFsCALHlxqoiCQCkSKM5pi0BgNhyY1WRBABSpNEc05YAQGy5sapIAgAp0miOaUsAILbcWFUkAYAUaTTHtCUAEFturCqSAECKNJpj2hIAiC03VhVJACBFGs0xbQkAxJYbq4okAJAijeaYtgQAYsuNVUUSAEiRRnNMWwIAseXGqiIJAKRIozmmLQGA2HJjVZEEAFKk0RzTlgBAbLmxqkgCACnSaI5pSwAgttxYVSQBgBRpNMe0JQAQW26sKpIAQIo02uuY94flN6+9MuwDkAxdEqrx3bflIFRO91IA0j3iuW4AkLn6yWmcEwCIc6BsN1cCAJmrn5zGOQGAOAfKdnMlAJC5+slpnBMAiHOgbDdXAgCZq5+cxjkBgDgHynZzJQCQufrJaZwTAIhzoGw3VwIAmaufnMY5AYA4B8p2cyUAkLn6yWmcEwCIc6BsN1cCAJmrn5zGOQGAOAfKdnMlAJC5+slpnBMAiHOgbDdXAgCZq5+cJmECv/+53B8Oy51C6fxOukIXqOFXAko4jkUBhOGUSUANB0BkRoNCFHEAhLmUSEAVB0AkxqN2Eco4AFJ7NsNPr44DIOEjUreADDgAUnc+Q0+eBQdAQsek5s0z4QBIzRkNO3U2HAAJG5V6N86IAyD15jTkxFlxACRkXGrdNDMOgNSa1eGnHY3j5mb5sH4K+KPnQfmwomea7PUrgQgcX94sn7x/XwUgDLV7AlE4jgcBiHs72dAzgUgcAPHsJHu5JxCNAyDuLWVDrwQUcMgAWcM4vlPw9/GhyCtg9smbgAoOCSBHHOtbae9/vEe8vq0GkryD7VH5u7+Wh+X7cuux15Y9rs1c6EP6KY7nw1wreMuhuSZnAmo4Ql9BXsIBkpyD7VG1Io4wIJdwgMRj3HLtoYojBMgWHCDJNeAt1SrjGA5kDw6QtIxdjrXqOIYCseAASY5Bt1SZAccwIC04foX/arn9+tr3k5WWxrKmPYEsOIYAccHx3BOQtE9n8A6ZcHQH4ooDJMGj3X77bDi6AumCAyTtUxq0Q0Yc3YB0xQGSoBG33zYrji5AhuAAiX1aB6/MjKMLkDWQD+uHzR6H9YEH92FR771RdhxdgPzYFCR7Z2m662fA0Q1IBJJXy3L3+e3AV67pRtrvQLPg6AoEJH4Dl2mnmXB0BwKSTKPdXutsOIYAAUn74GXYYTSOZdCbM8N+o3D0gzvPJONYzYqjR4IXvzgOJD0ij90THPvyv/rNiiDZF6jy1X98Wx6/L+vPvUb9G/Tfqp7HuQqEZ5Ke8Y/bGxy2rDcBiUCyflvK/fqVQg+2Y7HqNAFw2OdhMxCQ2EOOXAmOtvR3AQFJW9ijV4OjPfHdQEDSHvqIHcDhk7IJCEh8wu+1Czj8kjUDAYlfEzx3Aodnmuv3T7duN/rnJLy7db5j4Gid5v+vbwbCK4l/Uyw7gsOS2vU1LkCCkDysPye5v37E+a8AR78euwEBSb8mXdoZHH1zdwVyLHVt2O36eZ9hPwFfn0nKvpKAoy+O4+7uQEDSv2lPGfPBwwFRdwECkr6d45Wjb76nu3cDApI+TQRHn1zP7doVCEh8mwkO3zy37NYdCEi2tOH6NeC4nlGPK4YAAUlb68DRll/L6mFAQGJrEzhsuXmtGgoEJPvaBo59efW4ejgQkGxrIzi25dT7qhAgILnc1qF/kmIthe8kO9+PMCAgebkp4Oj9mrBv/1AgIPl3s8Cxb3hHXB0OBCQ/2wyOEeO+/x4SQKojAcf+wR21QgZIBJL16fTx6+vlblTYL90HHJHpX7+3FJBqSMBxfUCjr5ADUgUJOKJHf9v9JYHMjgQc24ZT4SpZILMiAYfC2G+vQRrI09ufd4fDwG8v6fjgDo7tg6lypTyQWZCAQ2Xk99WRAkh2JODYN5RKV6cBEoFk/RDfx89vl9uWhoGjJb34tamAZEMCjvgBb60gHZAsSMDROpoa61MCUUcCDo3h9qgiLRBVJODwGEudPVIDUUMCDp3B9qokPRAVJODwGkmtfaYAEo0EHFpD7VnNNEAikKx/euHT8b7rR2Heezbl0l58wcKopH/eZyogEUhGtgscI9OeFMisSMAxHseUryDPMa7PBWM/Bdyxf+DoGO6Vraf7L9bpeWdAwp+9jsMx9SvIDK8k4IjFUQJI1mcScMTjKAMkGxJwaOAoBSQLEnDo4CgH5AnJ/fqDvdAvizs3AuDQwlESiCoScOjhKAtEDQk4NHGUBqKCBBy6OMoDiUYCDm0cAHnqz/oT9+EP7uDQxwGQkx6NRAKOHDgA8p8+jUACjjw4APJCr3oiAUcuHAA5068eSMCRDwdALvTMEwk4cuIAyJW+eSABR14cANnQuxYk4NgQsPglU/9GoVf2FiTg8Eo/dh+AbMx/DxJwbAw1wWUA2dGkLUjAsSPQBJcCZGeTLiEBx84wE1wOEEOTXkICDkOQCZYAxNikUyTgMIaYYBlAGpp0RLIuP3x5szw0bMNS4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotP4B/zpSHgk1qeLgAAAABJRU5ErkJggg==" id="icon" x="582" y="-73" width="97.20533333333334" height="97.20533333333334" transform="translate(0 312.40198) translate(581.1707717249999 18.536) scale(1.65) translate(-582.58775 50.4)"/>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/static/img/logoFull.svg b/ping/frontend/static/img/logoFull.svg
new file mode 100644
index 0000000..505564a
--- /dev/null
+++ b/ping/frontend/static/img/logoFull.svg
@@ -0,0 +1,75 @@
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg282154" version="1.1" viewBox="64.45 264.58 895.08 203.68">
+ <metadata id="metadata282160">
+ <rdf:rdf>
+ <cc:work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ </cc:work>
+ </rdf:rdf>
+ </metadata>
+ <defs id="defs282158"/>
+ <linearGradient spreadMethod="pad" y2="30%" x2="-10%" y1="120%" x1="30%" id="3d_gradient2-logo-9cc91ee9-bcf4-468b-9589-30bc930545e6">
+ <stop id="stop282135" stop-opacity="1" stop-color="#ffffff" offset="0%"/>
+ <stop id="stop282137" stop-opacity="1" stop-color="#000000" offset="100%"/>
+ </linearGradient>
+ <linearGradient gradientTransform="rotate(-30)" spreadMethod="pad" y2="30%" x2="-10%" y1="120%" x1="30%" id="3d_gradient3-logo-9cc91ee9-bcf4-468b-9589-30bc930545e6">
+ <stop id="stop282140" stop-opacity="1" stop-color="#ffffff" offset="0%"/>
+ <stop id="stop282142" stop-opacity="1" stop-color="#cccccc" offset="50%"/>
+ <stop id="stop282144" stop-opacity="1" stop-color="#000000" offset="100%"/>
+ </linearGradient>
+ <g id="logo-group">
+ <image xlink:href="" id="container" style="display: none;" x="272" y="144" width="480" height="480" transform="translate(0 0)"/>
+ <g id="logo-center" transform="translate(5.684341886080802e-14 0)">
+ <image xlink:href="" id="icon_container" style="display: none;" x="0" y="0"/>
+ <g id="slogan" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" transform="translate(0 0)">
+ <path id="path282162" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 266.17275,-13.12 v 3.872 h 3.584 v 1.824 c 0,1.984 -1.6,3.584 -3.584,3.584 -1.984,0 -3.584,-1.6 -3.584,-3.584 v -7.488 c 0,-1.472 0.896,-2.752 2.208,-3.328 1.344,-0.544 2.88,-0.224 3.904,0.8 l 2.752,-2.752 c -2.144,-2.112 -5.344,-2.752 -8.128,-1.6 -2.784,1.152 -4.608,3.84 -4.576,6.88 v 7.488 c 0,4.096 3.328,7.392 7.424,7.392 4.096,0 7.424,-3.296 7.456,-7.392 v -5.696 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(252.41685344999996 54.29372769) scale(0.91) translate(-258.74834 22.358541)"/>
+ <path id="path282164" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 281.40225,-14.08 c -0.448,0 -0.928,0.064 -1.376,0.192 v -0.192 h -3.84 V 0.032 h 3.84 v -8.864 c 0,-0.544 0.352,-1.056 0.864,-1.28 0.512,-0.192 1.088,-0.096 1.504,0.32 l 2.72,-2.752 c -0.992,-0.992 -2.304,-1.536 -3.712,-1.536 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(270.10535155 61.8272) scale(0.91) translate(-276.18625 14.08)"/>
+ <path id="path282166" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 292.28425,-3.936 c -0.576,0.032 -1.152,-0.128 -1.632,-0.416 l 4.288,-1.792 0.544,-0.224 3.904,-1.6 -0.768,-1.792 v -0.032 0 -0.032 h -0.032 v -0.032 0 -0.032 0 l -0.032,-0.032 c -0.064,-0.128 -0.128,-0.256 -0.192,-0.384 0,-0.032 -0.032,-0.096 -0.064,-0.128 -0.064,-0.096 -0.128,-0.192 -0.16,-0.32 -0.032,-0.032 -0.064,-0.096 -0.096,-0.128 -0.064,-0.064 -0.096,-0.16 -0.16,-0.224 v 0 c -1.952,-2.752 -5.568,-3.712 -8.64,-2.336 -3.04,1.376 -4.704,4.736 -3.968,8 v 0.032 c 0.16,0.576 0.352,1.12 0.608,1.632 v 0 c 0.224,0.384 0.448,0.736 0.704,1.088 v 0 c 1.408,1.728 3.552,2.72 5.76,2.688 2.112,0 3.808,-0.64 5.632,-2.24 l -2.496,-2.944 c -1.152,0.992 -2.048,1.248 -3.2,1.248 z m -3.104,-3.584 c 0.096,-1.056 0.8,-2.016 1.792,-2.432 0.32,-0.16 0.704,-0.256 1.088,-0.224 0.672,0 1.344,0.224 1.888,0.64 0,0 0.032,0.032 0.032,0.032 l -2.368,0.992 -2.304,0.96 -0.128,0.064 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(280.03966685000006 61.84307404) scale(0.91) translate(-285.10308 14.062556)"/>
+ <path id="path282168" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 308.15925,-3.936 c -0.576,0.032 -1.152,-0.128 -1.632,-0.416 l 4.288,-1.792 0.544,-0.224 3.904,-1.6 -0.768,-1.792 v -0.032 0 -0.032 h -0.032 v -0.032 0 -0.032 0 l -0.032,-0.032 c -0.064,-0.128 -0.128,-0.256 -0.192,-0.384 0,-0.032 -0.032,-0.096 -0.064,-0.128 -0.064,-0.096 -0.128,-0.192 -0.16,-0.32 -0.032,-0.032 -0.064,-0.096 -0.096,-0.128 -0.064,-0.064 -0.096,-0.16 -0.16,-0.224 v 0 c -1.952,-2.752 -5.568,-3.712 -8.64,-2.336 -3.04,1.376 -4.704,4.736 -3.968,8 v 0.032 c 0.16,0.576 0.352,1.12 0.608,1.632 v 0 c 0.224,0.384 0.448,0.736 0.704,1.088 v 0 c 1.408,1.728 3.552,2.72 5.76,2.688 2.112,0 3.808,-0.64 5.632,-2.24 l -2.496,-2.944 c -1.152,0.992 -2.048,1.248 -3.2,1.248 z m -3.104,-3.584 c 0.096,-1.056 0.8,-2.016 1.792,-2.432 0.32,-0.16 0.704,-0.256 1.088,-0.224 0.672,0 1.344,0.224 1.888,0.64 0,0 0.032,0.032 0.032,0.032 l -2.368,0.992 -2.304,0.96 -0.128,0.064 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(296.3059168500001 61.84307404) scale(0.91) translate(-300.97808 14.062556)"/>
+ <path id="path282170" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 323.36225,-14.08 c -0.8,0 -1.6,0.16 -2.336,0.448 v -0.448 h -3.84 V 0.032 h 3.84 v -7.936 c 0,-1.28 1.056,-2.304 2.336,-2.304 1.28,0 2.304,1.024 2.304,2.304 v 7.936 h 3.872 v -7.936 c 0,-3.392 -2.752,-6.176 -6.176,-6.176 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(312.87535155000006 61.8272) scale(0.91) translate(-317.18625 14.08)"/>
+ <path id="path282172" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 345.15125,0 v -14.048 h -3.84 V 0 Z m 0,-18.208 v -4.096 h -3.84 v 4.096 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(336.64910155000007 54.343360000000004) scale(0.91) translate(-341.31125 22.304)"/>
+ <path id="path282174" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 353.92475,-14.08 c -0.8,0 -1.6,0.16 -2.336,0.448 v -0.448 h -3.84 V 0.032 h 3.84 v -7.936 c 0,-1.28 1.056,-2.304 2.336,-2.304 1.28,0 2.304,1.024 2.304,2.304 v 7.936 h 3.872 v -7.936 c 0,-3.392 -2.752,-6.176 -6.176,-6.176 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(344.3272265500001 61.8272) scale(0.91) translate(-347.74875 14.08)"/>
+ <path id="path282176" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 373.37425,-14.08 -3.744,9.024 -3.744,-9.024 h -4.16 l 5.824,14.112 h 4.192 l 5.824,-14.112 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(358.8667515500001 61.8272) scale(0.91) translate(-361.72625 14.08)"/>
+ <path id="path282178" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 385.22175,-3.936 c -0.576,0.032 -1.152,-0.128 -1.632,-0.416 l 4.288,-1.792 0.544,-0.224 3.904,-1.6 -0.768,-1.792 v -0.032 0 -0.032 h -0.032 v -0.032 0 -0.032 0 l -0.032,-0.032 c -0.064,-0.128 -0.128,-0.256 -0.192,-0.384 0,-0.032 -0.032,-0.096 -0.064,-0.128 -0.064,-0.096 -0.128,-0.192 -0.16,-0.32 -0.032,-0.032 -0.064,-0.096 -0.096,-0.128 -0.064,-0.064 -0.096,-0.16 -0.16,-0.224 v 0 c -1.952,-2.752 -5.568,-3.712 -8.64,-2.336 -3.04,1.376 -4.704,4.736 -3.968,8 v 0.032 c 0.16,0.576 0.352,1.12 0.608,1.632 v 0 c 0.224,0.384 0.448,0.736 0.704,1.088 v 0 c 1.408,1.728 3.552,2.72 5.76,2.688 2.112,0 3.808,-0.64 5.632,-2.24 l -2.496,-2.944 c -1.152,0.992 -2.048,1.248 -3.2,1.248 z m -3.104,-3.584 c 0.096,-1.056 0.8,-2.016 1.792,-2.432 0.32,-0.16 0.704,-0.256 1.088,-0.224 0.672,0 1.344,0.224 1.888,0.64 0,0 0.032,0.032 0.032,0.032 l -2.368,0.992 -2.304,0.96 -0.128,0.064 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(375.53279185000014 61.84307404) scale(0.91) translate(-378.04058 14.062556)"/>
+ <path id="path282180" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 403.72075,-7.648 c -0.832,-0.864 -1.984,-1.312 -3.168,-1.312 h -2.304 c -0.352,0 -0.64,-0.288 -0.64,-0.64 0,-0.32 0.288,-0.608 0.64,-0.608 h 5.472 v -3.872 h -5.472 c -2.496,0 -4.512,2.016 -4.512,4.48 0,2.496 2.016,4.512 4.512,4.512 h 2.304 c 0.352,0 0.608,0.256 0.608,0.608 0,0.352 -0.256,0.608 -0.608,0.608 h -5.504 V 0 h 5.568 c 1.792,-0.032 3.424,-1.12 4.096,-2.784 0.672,-1.664 0.288,-3.584 -0.992,-4.864 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(391.63630655000014 61.8272) scale(0.91) translate(-393.73675 14.08)"/>
+ <path id="path282182" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 413.29975,-10.208 v -3.872 h -1.824 v -8.288 h -3.872 v 8.288 h -1.12 v 3.872 h 1.12 v 6.432 c 0,2.08 1.696,3.776 3.776,3.776 h 1.92 v -3.872 h -1.824 v -6.336 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(405.05607655000017 54.285120000000006) scale(0.91) translate(-406.48375 22.368)"/>
+ <path id="path282184" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 419.40125,0 v -14.048 h -3.84 V 0 Z m 0,-18.208 v -4.096 h -3.84 v 4.096 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(415.1366015500002 54.343360000000004) scale(0.91) translate(-415.56125 22.304)"/>
+ <path id="path282186" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 428.17475,-14.08 c -0.8,0 -1.6,0.16 -2.336,0.448 v -0.448 h -3.84 V 0.032 h 3.84 v -7.936 c 0,-1.28 1.056,-2.304 2.336,-2.304 1.28,0 2.304,1.024 2.304,2.304 v 7.936 h 3.872 v -7.936 c 0,-3.392 -2.752,-6.176 -6.176,-6.176 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(422.8147265500002 61.8272) scale(0.91) translate(-421.99875 14.08)"/>
+ <path id="path282188" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 450.60025,-14.08 c -0.992,0 -1.984,0.416 -2.688,1.12 -0.064,0.064 -0.128,0.128 -0.192,0.192 -2.816,-2.016 -6.752,-1.664 -9.152,0.864 -2.432,2.528 -2.624,6.432 -0.48,9.216 -1.376,1.216 -1.856,3.2 -1.184,4.928 0.672,1.728 2.336,2.88 4.16,2.88 h 5.152 c 0.32,0 0.608,0.256 0.608,0.608 0,0.32 -0.288,0.608 -0.608,0.608 h -4.512 v 3.872 h 4.512 c 2.464,0 4.48,-2.016 4.48,-4.48 0,-2.496 -2.016,-4.48 -4.48,-4.48 h -5.12 c -0.352,0 -0.64,-0.288 -0.64,-0.608 0,-0.352 0.288,-0.64 0.64,-0.64 h 2.56 c 1.856,0.032 3.648,-0.736 4.96,-2.048 1.312,-1.312 2.08,-3.104 2.08,-4.992 v -3.168 h 1.824 v -3.872 z m -6.944,3.872 c 1.28,0 2.432,0.768 2.912,1.984 0.48,1.184 0.224,2.528 -0.672,3.456 -0.928,0.896 -2.272,1.152 -3.456,0.672 -1.184,-0.48 -1.984,-1.632 -1.984,-2.944 0,-1.728 1.44,-3.168 3.2,-3.168 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(437.9245940500003 61.8272) scale(0.91) translate(-436.603 14.08)"/>
+ <path id="path282190" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 478.68675,-14.08 c -1.6,0 -3.104,0.608 -4.256,1.696 -1.76,-1.664 -4.32,-2.144 -6.592,-1.248 v -0.448 h -3.84 V 0 h 3.84 v -7.904 c 0,-1.28 1.056,-2.304 2.336,-2.304 1.28,0 2.304,1.024 2.304,2.304 v 7.936 h 3.872 v -7.936 c 0,-1.28 1.056,-2.304 2.336,-2.304 1.28,0 2.304,1.024 2.304,2.304 v 7.936 h 3.872 v -7.936 c 0,-3.392 -2.784,-6.176 -6.176,-6.176 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(464.67472655000023 61.8272) scale(0.91) translate(-463.99875 14.08)"/>
+ <path id="path282192" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 497.32425,-14.08 v 0.768 c -2.976,-1.504 -6.56,-0.704 -8.672,1.856 -2.08,2.592 -2.08,6.272 0,8.864 2.112,2.56 5.696,3.36 8.672,1.856 v 0.768 h 3.872 V -14.08 Z m -3.168,10.24 c -1.76,0 -3.168,-1.44 -3.168,-3.2 0,-1.728 1.408,-3.168 3.168,-3.168 1.728,0 3.168,1.44 3.168,3.168 0,1.76 -1.44,3.168 -3.168,3.2 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(487.5098115500003 61.8272) scale(0.91) translate(-487.09225 14.08)"/>
+ <path id="path282194" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 513.63675,-22.368 v 9.056 c -2.976,-1.504 -6.56,-0.704 -8.672,1.856 -2.08,2.592 -2.08,6.272 0,8.864 2.112,2.56 5.696,3.36 8.672,1.856 v 0.768 h 3.872 v -22.4 z m -3.168,18.528 c -1.76,0 -3.168,-1.44 -3.168,-3.2 0,-1.728 1.408,-3.168 3.168,-3.168 1.728,0 3.168,1.44 3.168,3.168 0,1.76 -1.44,3.168 -3.168,3.2 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(504.1741865500003 54.285120000000006) scale(0.91) translate(-503.40475 22.368)"/>
+ <path id="path282196" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 526.90925,-3.936 c -0.576,0.032 -1.152,-0.128 -1.632,-0.416 l 4.288,-1.792 0.544,-0.224 3.904,-1.6 -0.768,-1.792 v -0.032 0 -0.032 h -0.032 v -0.032 0 -0.032 0 l -0.032,-0.032 c -0.064,-0.128 -0.128,-0.256 -0.192,-0.384 0,-0.032 -0.032,-0.096 -0.064,-0.128 -0.064,-0.096 -0.128,-0.192 -0.16,-0.32 -0.032,-0.032 -0.064,-0.096 -0.096,-0.128 -0.064,-0.064 -0.096,-0.16 -0.16,-0.224 v 0 c -1.952,-2.752 -5.568,-3.712 -8.64,-2.336 -3.04,1.376 -4.704,4.736 -3.968,8 v 0.032 c 0.16,0.576 0.352,1.12 0.608,1.632 v 0 c 0.224,0.384 0.448,0.736 0.704,1.088 v 0 c 1.408,1.728 3.552,2.72 5.76,2.688 2.112,0 3.808,-0.64 5.632,-2.24 l -2.496,-2.944 c -1.152,0.992 -2.048,1.248 -3.2,1.248 z m -3.104,-3.584 c 0.096,-1.056 0.8,-2.016 1.792,-2.432 0.32,-0.16 0.704,-0.256 1.088,-0.224 0.672,0 1.344,0.224 1.888,0.64 0,0 0.032,0.032 0.032,0.032 l -2.368,0.992 -2.304,0.96 -0.128,0.064 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(520.8484168500004 61.84307404) scale(0.91) translate(-519.72808 14.062556)"/>
+ <path id="path282198" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 551.97175,-3.936 c -0.576,0.032 -1.152,-0.128 -1.632,-0.416 l 4.288,-1.792 0.544,-0.224 3.904,-1.6 -0.768,-1.792 v -0.032 0 -0.032 h -0.032 v -0.032 0 -0.032 0 l -0.032,-0.032 c -0.064,-0.128 -0.128,-0.256 -0.192,-0.384 0,-0.032 -0.032,-0.096 -0.064,-0.128 -0.064,-0.096 -0.128,-0.192 -0.16,-0.32 -0.032,-0.032 -0.064,-0.096 -0.096,-0.128 -0.064,-0.064 -0.096,-0.16 -0.16,-0.224 v 0 c -1.952,-2.752 -5.568,-3.712 -8.64,-2.336 -3.04,1.376 -4.704,4.736 -3.968,8 v 0.032 c 0.16,0.576 0.352,1.12 0.608,1.632 v 0 c 0.224,0.384 0.448,0.736 0.704,1.088 v 0 c 1.408,1.728 3.552,2.72 5.76,2.688 2.112,0 3.808,-0.64 5.632,-2.24 l -2.496,-2.944 c -1.152,0.992 -2.048,1.248 -3.2,1.248 z m -3.104,-3.584 c 0.096,-1.056 0.8,-2.016 1.792,-2.432 0.32,-0.16 0.704,-0.256 1.088,-0.224 0.672,0 1.344,0.224 1.888,0.64 0,0 0.032,0.032 0.032,0.032 l -2.368,0.992 -2.304,0.96 -0.128,0.064 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(545.4752918500004 61.84307404) scale(0.91) translate(-544.79058 14.062556)"/>
+ <path id="path282200" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 570.88675,-14.08 v 0.768 c -2.976,-1.504 -6.56,-0.704 -8.672,1.856 -2.08,2.592 -2.08,6.272 0,8.864 2.112,2.56 5.696,3.36 8.672,1.856 v 0.768 h 3.872 V -14.08 Z m -3.168,10.24 c -1.76,0 -3.168,-1.44 -3.168,-3.2 0,-1.728 1.408,-3.168 3.168,-3.168 1.728,0 3.168,1.44 3.168,3.168 0,1.76 -1.44,3.168 -3.168,3.2 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(561.7316865500004 61.8272) scale(0.91) translate(-560.65475 14.08)"/>
+ <path id="path282202" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 586.78325,-7.648 c -0.832,-0.864 -1.984,-1.312 -3.168,-1.312 h -2.304 c -0.352,0 -0.64,-0.288 -0.64,-0.64 0,-0.32 0.288,-0.608 0.64,-0.608 h 5.472 v -3.872 h -5.472 c -2.496,0 -4.512,2.016 -4.512,4.48 0,2.496 2.016,4.512 4.512,4.512 h 2.304 c 0.352,0 0.608,0.256 0.608,0.608 0,0.352 -0.256,0.608 -0.608,0.608 h -5.504 V 0 h 5.568 c 1.792,-0.032 3.424,-1.12 4.096,-2.784 0.672,-1.664 0.288,-3.584 -0.992,-4.864 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(578.2431815500004 61.8272) scale(0.91) translate(-576.79925 14.08)"/>
+ <path id="path282204" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 598.66625,-14.08 v 7.904 c 0,1.28 -1.024,2.336 -2.304,2.336 -1.28,0 -2.336,-1.056 -2.336,-2.336 v -7.904 h -3.872 v 7.904 c 0.032,2.048 1.024,3.968 2.752,5.12 1.696,1.152 3.872,1.376 5.76,0.608 v 3.616 c 0,1.28 -1.024,2.336 -2.304,2.336 -1.28,0 -2.336,-1.056 -2.336,-2.336 h -3.872 c 0,3.424 2.784,6.208 6.208,6.208 3.424,0 6.176,-2.784 6.176,-6.208 V -14.08 Z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(592.2162315500003 61.8272) scale(0.91) translate(-590.15425 14.08)"/>
+ <path id="path282206" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 618.15125,0.032 v -22.368 h -3.84 V 0.032 Z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(616.0191015500003 54.31424) scale(0.91) translate(-614.31125 22.336)"/>
+ <path id="path282208" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 624.58875,0 v -14.048 h -3.84 V 0 Z m 0,-18.208 v -4.096 h -3.84 v 4.096 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(623.6972265500003 54.343360000000004) scale(0.91) translate(-620.74875 22.304)"/>
+ <path id="path282210" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 638.61025,-14.048 h -3.872 v 1.92 c 0,1.024 -0.832,1.856 -1.856,1.856 -0.608,0 -1.248,0.096 -1.856,0.288 v -12.384 h -3.872 v 22.4 h 3.872 v -4.608 c 0,-0.64 0.352,-1.28 0.928,-1.6 0.576,-0.32 1.28,-0.32 1.856,0 0.576,0.32 0.928,0.96 0.928,1.6 v 4.608 h 3.872 v -4.608 c 0,-1.376 -0.512,-2.72 -1.44,-3.776 0.928,-1.024 1.44,-2.368 1.44,-3.776 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(631.3462315500004 54.285120000000006) scale(0.91) translate(-627.15425 22.368)"/>
+ <path id="path282212" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 648.03425,-3.936 c -0.576,0.032 -1.152,-0.128 -1.632,-0.416 l 4.288,-1.792 0.544,-0.224 3.904,-1.6 -0.768,-1.792 v -0.032 0 -0.032 h -0.032 v -0.032 0 -0.032 0 l -0.032,-0.032 c -0.064,-0.128 -0.128,-0.256 -0.192,-0.384 0,-0.032 -0.032,-0.096 -0.064,-0.128 -0.064,-0.096 -0.128,-0.192 -0.16,-0.32 -0.032,-0.032 -0.064,-0.096 -0.096,-0.128 -0.064,-0.064 -0.096,-0.16 -0.16,-0.224 v 0 c -1.952,-2.752 -5.568,-3.712 -8.64,-2.336 -3.04,1.376 -4.704,4.736 -3.968,8 v 0.032 c 0.16,0.576 0.352,1.12 0.608,1.632 v 0 c 0.224,0.384 0.448,0.736 0.704,1.088 v 0 c 1.408,1.728 3.552,2.72 5.76,2.688 2.112,0 3.808,-0.64 5.632,-2.24 l -2.496,-2.944 c -1.152,0.992 -2.048,1.248 -3.2,1.248 z m -3.104,-3.584 c 0.096,-1.056 0.8,-2.016 1.792,-2.432 0.32,-0.16 0.704,-0.256 1.088,-0.224 0.672,0 1.344,0.224 1.888,0.64 0,0 0.032,0.032 0.032,0.032 l -2.368,0.992 -2.304,0.96 -0.128,0.064 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(645.6321668500004 61.84307404) scale(0.91) translate(-640.85308 14.062556)"/>
+ <path id="path282214" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 673.28875,-14.08 c -1.12,0 -2.208,0.256 -3.2,0.768 v -9.056 h -3.84 V 0 h 3.84 v -0.736 c 2.624,1.312 5.76,0.896 7.904,-1.056 2.176,-1.984 2.912,-5.056 1.856,-7.776 -1.056,-2.72 -3.648,-4.512 -6.56,-4.512 z m 0,10.24 c -1.76,0 -3.2,-1.44 -3.2,-3.2 0,-1.728 1.44,-3.168 3.2,-3.168 1.728,0 3.168,1.44 3.168,3.168 0,1.76 -1.44,3.168 -3.168,3.2 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(670.5622265500004 54.285120000000006) scale(0.91) translate(-666.24875 22.368)"/>
+ <path id="path282216" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 687.77725,-14.08 c -0.448,0 -0.928,0.064 -1.376,0.192 v -0.192 h -3.84 V 0.032 h 3.84 v -8.864 c 0,-0.544 0.352,-1.056 0.864,-1.28 0.512,-0.192 1.088,-0.096 1.504,0.32 l 2.72,-2.752 c -0.992,-0.992 -2.304,-1.536 -3.712,-1.536 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(687.2266015500004 61.8272) scale(0.91) translate(-682.56125 14.08)"/>
+ <path id="path282218" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 698.65225,-14.08 c -0.448,0 -0.928,0.064 -1.376,0.192 v -0.192 h -3.84 V 0.032 h 3.84 v -8.864 c 0,-0.544 0.352,-1.056 0.864,-1.28 0.512,-0.192 1.088,-0.096 1.504,0.32 l 2.72,-2.752 c -0.992,-0.992 -2.304,-1.536 -3.712,-1.536 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(698.9428515500003 61.8272) scale(0.91) translate(-693.43625 14.08)"/>
+ <path id="path282220" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 720.53875,-14.08 c -1.12,0 -2.208,0.256 -3.2,0.768 v -9.056 h -3.84 V 0 h 3.84 v -0.736 c 2.624,1.312 5.76,0.896 7.904,-1.056 2.176,-1.984 2.912,-5.056 1.856,-7.776 -1.056,-2.72 -3.648,-4.512 -6.56,-4.512 z m 0,10.24 c -1.76,0 -3.2,-1.44 -3.2,-3.2 0,-1.728 1.44,-3.168 3.2,-3.168 1.728,0 3.168,1.44 3.168,3.168 0,1.76 -1.44,3.168 -3.168,3.2 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(719.0197265500003 54.285120000000006) scale(0.91) translate(-713.49875 22.368)"/>
+ <path id="path282222" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 735.02725,-14.08 c -0.448,0 -0.928,0.064 -1.376,0.192 v -0.192 h -3.84 V 0.032 h 3.84 v -8.864 c 0,-0.544 0.352,-1.056 0.864,-1.28 0.512,-0.192 1.088,-0.096 1.504,0.32 l 2.72,-2.752 c -0.992,-0.992 -2.304,-1.536 -3.712,-1.536 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(735.6841015500003 61.8272) scale(0.91) translate(-729.81125 14.08)"/>
+ <path id="path282224" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="m 745.90225,-14.08 c -0.448,0 -0.928,0.064 -1.376,0.192 v -0.192 h -3.84 V 0.032 h 3.84 v -8.864 c 0,-0.544 0.352,-1.056 0.864,-1.28 0.512,-0.192 1.088,-0.096 1.504,0.32 l 2.72,-2.752 c -0.992,-0.992 -2.304,-1.536 -3.712,-1.536 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(747.4003515500002 61.8272) scale(0.91) translate(-740.68625 14.08)"/>
+ <path id="path282226" style="font-style:normal;font-weight:700;font-size:32px;line-height:1;font-family:'Brandmark Sans 4 Spectrum';font-variant-ligatures:none;text-align:center;text-anchor:middle" d="M 765.26075,0.288 V -4.32 h -4.512 v 4.608 z m 0,-6.368 v -18.56 h -4.512 v 18.56 z" stroke-width="0" stroke-linejoin="miter" stroke-miterlimit="2" fill="#7bc74d" stroke="#7bc74d" transform="translate(-5.684341886080802e-14 384.32698) translate(767.4772265500002 52.217600000000004) scale(0.91) translate(-760.74875 24.64)"/>
+ </g>
+ <g id="title" style="font-style:normal;font-weight:400;font-size:72px;line-height:1;font-family:'Brandmark Dots 1 Color';font-variant-ligatures:normal;text-align:center;text-anchor:middle" transform="translate(0 0)">
+ <g id="path282229" aria-label="P" transform="translate(0 283.34614) translate(66.20587072499995 18.536) scale(1.65) translate(-270.48781 50.4)"> <path class="c1" d="M116.52588,101.7917c-1.36816,2.23242-4.32031,2.95215-6.55273,1.51172 c-2.30469-1.36719-2.95215-4.32031-1.58398-6.55176c0.86426-1.44043,1.44043-3.09668,1.44043-4.6084 c0-1.87207-0.43262-7.77734-6.19336-7.77734H90.24365v36.0752c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.16016-4.75293-4.75293V79.5417c0-2.5918,2.16016-4.75195,4.75293-4.75195h18.2168 c10.80176,0,15.69727,9,15.69727,17.35352C119.3335,95.3835,118.32568,98.83955,116.52588,101.7917z" transform="translate(189.82131 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M99.74854,109.35225c-2.59277,0-4.75293-2.16016-4.75293-4.82422c0-2.5918,2.16016-4.75195,4.75293-4.75195 c2.66406,0,4.75195,2.16016,4.75195,4.75195C104.50049,107.19209,102.4126,109.35225,99.74854,109.35225z" transform="translate(189.82131 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282231" aria-label="A" transform="translate(0 283.34614) translate(127.67317222499996 18.536) scale(1.65) translate(-307.74072 50.4)"> <path class="c1" d="M117.13755,104.6003l-12.81689-27.07422c-0.79199-1.65625-2.52051-2.73633-4.32031-2.73633 c-1.87207,0-3.52832,1.08008-4.32031,2.73633l-19.44189,40.82715c-1.08008,2.37598-0.07178,5.25684,2.3042,6.4082 c2.37598,1.08008,5.18457,0.07227,6.33643-2.30371l4.53662-9.50488h24.19385c1.65625,0,3.09619-0.86426,3.96045-2.16016 C119.22593,108.34444,117.92954,106.25655,117.13755,104.6003z M93.30357,104.74385l6.69678-14.11328l6.76855,14.11328H93.30357z" transform="translate(231.934901 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M124.19419,120.44112c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59229,0-4.75244-2.16016-4.75244-4.75293c0-2.66406,2.16016-4.82422,4.75244-4.82422 C122.03403,115.6169,124.19419,117.77705,124.19419,120.44112z" transform="translate(231.934901 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282233" aria-label="T" transform="translate(0 283.34614) translate(200.92322272499987 18.536) scale(1.65) translate(-352.13469 50.4)"> <path class="c1" d="M104.75244,120.44112c0,2.59277-2.08789,4.75293-4.75293,4.75293 c-2.66406,0-4.75195-2.16016-4.75195-4.75293v-36.0752H84.80615c-2.5918,0-4.75195-2.16016-4.75195-4.82422 c0-2.5918,2.16016-4.75195,4.75195-4.75195h15.19336c2.88086,0,4.75293,2.16016,4.75293,4.75195V120.44112z" transform="translate(272.08049 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M119.9458,79.5417c0,2.66406-2.16016,4.82422-4.75293,4.82422c-2.66406,0-4.82422-2.16016-4.82422-4.82422 c0-2.5918,2.16016-4.75195,4.82422-4.75195C117.78564,74.78975,119.9458,76.94991,119.9458,79.5417z" transform="translate(272.08049 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282235" aria-label="A" transform="translate(0 283.34614) translate(261.55521172499994 18.536) scale(1.65) translate(-388.88135 50.4)"> <path class="c1" d="M117.13755,104.6003l-12.81689-27.07422c-0.79199-1.65625-2.52051-2.73633-4.32031-2.73633 c-1.87207,0-3.52832,1.08008-4.32031,2.73633l-19.44189,40.82715c-1.08008,2.37598-0.07178,5.25684,2.3042,6.4082 c2.37598,1.08008,5.18457,0.07227,6.33643-2.30371l4.53662-9.50488h24.19385c1.65625,0,3.09619-0.86426,3.96045-2.16016 C119.22593,108.34444,117.92954,106.25655,117.13755,104.6003z M93.30357,104.74385l6.69678-14.11328l6.76855,14.11328H93.30357z" transform="translate(313.075531 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M124.19419,120.44112c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59229,0-4.75244-2.16016-4.75244-4.75293c0-2.66406,2.16016-4.82422,4.75244-4.82422 C122.03403,115.6169,124.19419,117.77705,124.19419,120.44112z" transform="translate(313.075531 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282237" aria-label="P" transform="translate(0 283.34614) translate(355.5488477249999 18.536) scale(1.65) translate(-445.84719 50.4)"> <path class="c1" d="M116.52588,101.7917c-1.36816,2.23242-4.32031,2.95215-6.55273,1.51172 c-2.30469-1.36719-2.95215-4.32031-1.58398-6.55176c0.86426-1.44043,1.44043-3.09668,1.44043-4.6084 c0-1.87207-0.43262-7.77734-6.19336-7.77734H90.24365v36.0752c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.16016-4.75293-4.75293V79.5417c0-2.5918,2.16016-4.75195,4.75293-4.75195h18.2168 c10.80176,0,15.69727,9,15.69727,17.35352C119.3335,95.3835,118.32568,98.83955,116.52588,101.7917z" transform="translate(365.18069 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M99.74854,109.35225c-2.59277,0-4.75293-2.16016-4.75293-4.82422c0-2.5918,2.16016-4.75195,4.75293-4.75195 c2.66406,0,4.75195,2.16016,4.75195,4.75195C104.50049,107.19209,102.4126,109.35225,99.74854,109.35225z" transform="translate(365.18069 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282239" aria-label="I" transform="translate(0 283.34614) translate(435.39543322499986 16.39760000000001) scale(1.65) translate(-494.23906 51.696)"> <path class="c3" d="M95.21143,78.2458c0-2.59277,2.16016-4.75293,4.75293-4.75293c2.66406,0,4.82422,2.16016,4.82422,4.75293 c0,2.66406-2.16016,4.82422-4.82422,4.82422C97.37158,83.07002,95.21143,80.90987,95.21143,78.2458z" transform="translate(399.02763 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> <path class="c1" d="M95.21143,120.44112V92.57491c0-2.5918,2.16016-4.75195,4.75293-4.75195 c2.66406,0,4.82422,2.16016,4.82422,4.75195v27.86621c0,2.59277-2.16016,4.75293-4.82422,4.75293 C97.37158,125.19405,95.21143,123.03389,95.21143,120.44112z" transform="translate(399.02763 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> </g>
+ <g id="path282241" aria-label="M" transform="translate(0 283.34614) translate(475.07278522499985 18.550630549999994) scale(1.65) translate(-518.28594 50.391133)"> <path class="c1" d="M117.89355,95.59932l-14.04102,27.14648c-0.86426,1.51172-2.44824,2.44824-4.17676,2.44824 c-1.72754,0-3.31152-0.93652-4.17578-2.52051L82.10645,96.03096v24.41016c0,2.59277-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.16016-4.75293-4.75293V79.5417c0-2.16016,1.44043-4.03223,3.60059-4.6084 c2.08789-0.50391,4.32031,0.43262,5.3291,2.37598l18.28906,34.70703l18.79395-34.77832 c1.00781-1.87207,3.24023-2.80859,5.32813-2.30469c2.08789,0.57617,3.60059,2.44824,3.60059,4.6084v26.57031 c0,2.59277-2.16016,4.75293-4.82422,4.75293c-2.59277,0-4.75293-2.16016-4.75293-4.75293V95.59932z" transform="translate(445.75664 -125.18939)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M122.64648,125.19405c-2.59277,0-4.75293-2.16016-4.75293-4.75293 c0-2.66406,2.16016-4.82422,4.75293-4.82422c2.66406,0,4.82422,2.16016,4.82422,4.82422 C127.4707,123.03389,125.31055,125.19405,122.64648,125.19405z" transform="translate(445.75664 -125.18939)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282243" aria-label="V" style="display: none;" transform="translate(0 404.62816) translate(624.0138635 18.536) scale(1.65) translate(-582.58775 50.4)"> <path class="c1" d="M104.3493,122.38545c-0.71973,1.72852-2.44824,2.87988-4.3916,2.87988 c-1.87207,0-3.60059-1.15137-4.32031-2.87988l-17.8584-40.89941c-1.08008-2.44824,0-5.25684,2.44824-6.26465 c2.37695-1.08008,5.18457,0,6.26465,2.44824l13.53711,31.10645l7.77734-18.00098c1.00781-2.37695,3.81641-3.45703,6.26465-2.44824 c2.37598,1.08008,3.52832,3.8877,2.44824,6.33594L104.3493,122.38545z" transform="translate(505.227103 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M122.63934,79.5417c0,2.66406-2.08789,4.82422-4.75293,4.82422c-2.5918,0-4.75195-2.16016-4.75195-4.82422 c0-2.5918,2.16016-4.75195,4.75195-4.75195C120.55145,74.78975,122.63934,76.94991,122.63934,79.5417z" transform="translate(505.227103 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282245" aria-label="E" transform="translate(0 283.34614) translate(755.8694062749997 18.536) scale(1.65) translate(-636.53469 50.4)"> <path class="c1" d="M87.75879,125.19405c-2.5918,0-4.75195-2.16016-4.75195-4.75293V79.5417 c0-2.5918,2.16016-4.75195,4.75195-4.75195h9.9375c2.5918,0,4.75195,2.16016,4.75195,4.75195 c0,2.66406-2.16016,4.82422-4.75195,4.82422h-5.1123V95.3835h16.70508c2.66406,0,4.75195,1.94434,4.75195,4.6084 c0,2.5918-2.08789,4.53613-4.75195,4.53613H92.58398v11.08887h19.65723c2.66406,0,4.75195,2.16016,4.75195,4.82422 c0,2.59277-2.08789,4.75293-4.75195,4.75293H87.75879z" transform="translate(553.52785 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M112.02539,84.36592c-2.66406,0-4.82422-2.16016-4.82422-4.82422c0-2.5918,2.16016-4.75195,4.82422-4.75195 c2.5918,0,4.75195,2.16016,4.75195,4.75195C116.77734,82.20576,114.61719,84.36592,112.02539,84.36592z" transform="translate(553.52785 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ <g id="path282247" aria-label="S" transform="translate(0 283.34614) translate(825.0332812749998 16.39760000000001) scale(1.65) translate(-678.45219 51.696)"> <path class="c3" d="M90.67529,115.04073c0,2.66406-2.16016,4.75293-4.82422,4.75293 c-2.59277,0-4.75293-2.08887-4.75293-4.75293s2.16016-4.75195,4.75293-4.75195 C88.51514,110.28877,90.67529,112.37666,90.67529,115.04073z" transform="translate(597.35405 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> <path class="c1" d="M102.48486,126.48994c-3.74512,0-8.78516-1.44043-8.78516-5.1123 c0-3.02441,2.01563-4.68066,4.39258-4.53613c2.44824,0.14355,5.1123,1.00781,7.7041-0.2168 c2.0166-0.93555,3.52832-2.73633,3.52832-5.25586c0-3.02441-3.38379-4.96875-10.72852-7.63281 c-6.625-2.37598-16.56152-5.32813-16.63379-15.19336c0-3.74414,1.44043-7.27246,4.10449-10.00879 c2.30469-2.30469,6.55273-5.04102,13.96973-5.04102c8.42383,0,14.04102,4.46484,15.91309,7.12891 c1.2959,1.72852,1.08008,4.03223-0.21582,5.68848c-1.72852,2.16016-4.32031,1.94434-6.12109,0.36035 c-1.2959-1.15234-4.32031-4.17676-9.86426-4.17676c-4.8252,0-8.20898,2.52051-8.20898,6.04883 c0,2.30371,2.52051,4.24805,10.00879,7.12891c9.2168,3.52832,17.35352,7.41602,17.35352,16.27344 C118.90186,119.07295,113.93311,126.48994,102.48486,126.48994z" transform="translate(597.35405 -125.18887)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> </g>
+ <g id="path282249" aria-label="T" transform="translate(0 283.34614) translate(891.9789292749999 18.536) scale(1.65) translate(-719.02531 50.4)"> <path class="c1" d="M104.75244,120.44112c0,2.59277-2.08789,4.75293-4.75293,4.75293 c-2.66406,0-4.75195-2.16016-4.75195-4.75293v-36.0752H84.80615c-2.5918,0-4.75195-2.16016-4.75195-4.82422 c0-2.5918,2.16016-4.75195,4.75195-4.75195h15.19336c2.88086,0,4.75293,2.16016,4.75293,4.75195V120.44112z" transform="translate(638.97111 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#47a200" stroke="#47a200"/> <path class="c3" d="M119.9458,79.5417c0,2.66406-2.16016,4.82422-4.75293,4.82422c-2.66406,0-4.82422-2.16016-4.82422-4.82422 c0-2.5918,2.16016-4.75195,4.82422-4.75195C117.78564,74.78975,119.9458,76.94991,119.9458,79.5417z" transform="translate(638.97111 -125.18975)" stroke-width="0.8" stroke-linejoin="miter" stroke-miterlimit="2" fill="#6bff25" stroke="#6bff25"/> </g>
+ </g>
+ <image xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAIoUlEQVR4Xu3dzXYTRxCG4TEn1wXsSe4I/Ad3BOxJ7ioblBHYHCWxpJnq6q6vul7W0z3VX9VzxMiyfLPwjwRI4GwCN2RDAiRwPgGAMB0kcCEBgDAeJAAQZoAEbAnwCmLLjVVFEgBIkUZzTFsCALHlxqoiCQCkSKM5pi0BgNhyY1WRBABSpNEc05YAQGy5sapIAgAp0miOaUsAILbcWFUkAYAUaTTHtCUAEFturCqSAECKNJpj2hIAiC03VhVJACBFGs0xbQkAxJYbq4okAJAijeaYtgQAYsuNVUUSAEiRRnNMWwIAseXGqiIJAKRIozmmLQGA2HJjVZEEAFKk0RzTlgBAbLmxqkgCACnSaI5pSwAgttxYVSQBgBRpNMe0JQAQW26sKpIAQIo02uuY94flN6+9MuwDkAxdEqrx3bflIFRO91IA0j3iuW4AkLn6yWmcEwCIc6BsN1cCAJmrn5zGOQGAOAfKdnMlAJC5+slpnBMAiHOgbDdXAgCZq5+cxjkBgDgHynZzJQCQufrJaZwTAIhzoGw3VwIAmaufnMY5AYA4B8p2cyUAkLn6yWmcEwCIc6BsN1cCAJmrn5zGOQGAOAfKdnMlAJC5+slpnBMAiHOgbDdXAgCZq5+cJmECv/+53B8Oy51C6fxOukIXqOFXAko4jkUBhOGUSUANB0BkRoNCFHEAhLmUSEAVB0AkxqN2Eco4AFJ7NsNPr44DIOEjUreADDgAUnc+Q0+eBQdAQsek5s0z4QBIzRkNO3U2HAAJG5V6N86IAyD15jTkxFlxACRkXGrdNDMOgNSa1eGnHY3j5mb5sH4K+KPnQfmwomea7PUrgQgcX94sn7x/XwUgDLV7AlE4jgcBiHs72dAzgUgcAPHsJHu5JxCNAyDuLWVDrwQUcMgAWcM4vlPw9/GhyCtg9smbgAoOCSBHHOtbae9/vEe8vq0GkryD7VH5u7+Wh+X7cuux15Y9rs1c6EP6KY7nw1wreMuhuSZnAmo4Ql9BXsIBkpyD7VG1Io4wIJdwgMRj3HLtoYojBMgWHCDJNeAt1SrjGA5kDw6QtIxdjrXqOIYCseAASY5Bt1SZAccwIC04foX/arn9+tr3k5WWxrKmPYEsOIYAccHx3BOQtE9n8A6ZcHQH4ooDJMGj3X77bDi6AumCAyTtUxq0Q0Yc3YB0xQGSoBG33zYrji5AhuAAiX1aB6/MjKMLkDWQD+uHzR6H9YEH92FR771RdhxdgPzYFCR7Z2m662fA0Q1IBJJXy3L3+e3AV67pRtrvQLPg6AoEJH4Dl2mnmXB0BwKSTKPdXutsOIYAAUn74GXYYTSOZdCbM8N+o3D0gzvPJONYzYqjR4IXvzgOJD0ij90THPvyv/rNiiDZF6jy1X98Wx6/L+vPvUb9G/Tfqp7HuQqEZ5Ke8Y/bGxy2rDcBiUCyflvK/fqVQg+2Y7HqNAFw2OdhMxCQ2EOOXAmOtvR3AQFJW9ijV4OjPfHdQEDSHvqIHcDhk7IJCEh8wu+1Czj8kjUDAYlfEzx3Aodnmuv3T7duN/rnJLy7db5j4Gid5v+vbwbCK4l/Uyw7gsOS2vU1LkCCkDysPye5v37E+a8AR78euwEBSb8mXdoZHH1zdwVyLHVt2O36eZ9hPwFfn0nKvpKAoy+O4+7uQEDSv2lPGfPBwwFRdwECkr6d45Wjb76nu3cDApI+TQRHn1zP7doVCEh8mwkO3zy37NYdCEi2tOH6NeC4nlGPK4YAAUlb68DRll/L6mFAQGJrEzhsuXmtGgoEJPvaBo59efW4ejgQkGxrIzi25dT7qhAgILnc1qF/kmIthe8kO9+PMCAgebkp4Oj9mrBv/1AgIPl3s8Cxb3hHXB0OBCQ/2wyOEeO+/x4SQKojAcf+wR21QgZIBJL16fTx6+vlblTYL90HHJHpX7+3FJBqSMBxfUCjr5ADUgUJOKJHf9v9JYHMjgQc24ZT4SpZILMiAYfC2G+vQRrI09ufd4fDwG8v6fjgDo7tg6lypTyQWZCAQ2Xk99WRAkh2JODYN5RKV6cBEoFk/RDfx89vl9uWhoGjJb34tamAZEMCjvgBb60gHZAsSMDROpoa61MCUUcCDo3h9qgiLRBVJODwGEudPVIDUUMCDp3B9qokPRAVJODwGkmtfaYAEo0EHFpD7VnNNEAikKx/euHT8b7rR2Heezbl0l58wcKopH/eZyogEUhGtgscI9OeFMisSMAxHseUryDPMa7PBWM/Bdyxf+DoGO6Vraf7L9bpeWdAwp+9jsMx9SvIDK8k4IjFUQJI1mcScMTjKAMkGxJwaOAoBSQLEnDo4CgH5AnJ/fqDvdAvizs3AuDQwlESiCoScOjhKAtEDQk4NHGUBqKCBBy6OMoDiUYCDm0cAHnqz/oT9+EP7uDQxwGQkx6NRAKOHDgA8p8+jUACjjw4APJCr3oiAUcuHAA5068eSMCRDwdALvTMEwk4cuIAyJW+eSABR14cANnQuxYk4NgQsPglU/9GoVf2FiTg8Eo/dh+AbMx/DxJwbAw1wWUA2dGkLUjAsSPQBJcCZGeTLiEBx84wE1wOEEOTXkICDkOQCZYAxNikUyTgMIaYYBlAGpp0RLIuP3x5szw0bMNS4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotPACDxPaAC4QQAItwcSotP4B/zpSHgk1qeLgAAAABJRU5ErkJggg==" id="icon" x="582" y="-73" width="97.20533333333334" height="97.20533333333334" transform="translate(0 283.34614) translate(581.1707717249999 18.536) scale(1.65) translate(-582.58775 50.4)"/>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/ping/frontend/svelte.config.js b/ping/frontend/svelte.config.js
new file mode 100644
index 0000000..1295460
--- /dev/null
+++ b/ping/frontend/svelte.config.js
@@ -0,0 +1,18 @@
+import adapter from '@sveltejs/adapter-auto';
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ // Consult https://svelte.dev/docs/kit/integrations
+ // for more information about preprocessors
+ preprocess: vitePreprocess(),
+
+ kit: {
+ // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
+ // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
+ // See https://svelte.dev/docs/kit/adapters for more information about adapters.
+ adapter: adapter()
+ }
+};
+
+export default config;
diff --git a/ping/frontend/tsconfig.json b/ping/frontend/tsconfig.json
new file mode 100644
index 0000000..0b2d886
--- /dev/null
+++ b/ping/frontend/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "moduleResolution": "bundler"
+ }
+ // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
+ // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
+ //
+ // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
+ // from the referenced tsconfig.json - TypeScript does not merge them in
+}
diff --git a/ping/frontend/vite.config.ts b/ping/frontend/vite.config.ts
new file mode 100644
index 0000000..ef26a3a
--- /dev/null
+++ b/ping/frontend/vite.config.ts
@@ -0,0 +1,30 @@
+import tailwindcss from '@tailwindcss/vite';
+import devtoolsJson from 'vite-plugin-devtools-json';
+import { sveltekit } from '@sveltejs/kit/vite';
+import { defineConfig, loadEnv } from 'vite';
+
+export default defineConfig(({ mode }) => {
+ // @ts-expect-error process is loaded
+ const env = loadEnv(mode, process.cwd());
+
+ console.log("Found API URL:", env.VITE_BACKEND_URL);
+
+ const API_URL = (env.VITE_BACKEND_URL ?? "http://127.0.1:8080");
+
+ return {
+ plugins: [tailwindcss(), sveltekit(), devtoolsJson()],
+ optimizeDeps: {
+ exclude: ['chart.js']
+ },
+ server: {
+ proxy: {
+ '/api': API_URL
+ },
+ allowedHosts: [
+ 'patapimvest.esteban-charvin.dev',
+ 'localhost',
+ '127.0.0.1'
+ ],
+ }
+ }
+});