From 27636988e6ecdac888ba1e6ffba8d172518bc707 Mon Sep 17 00:00:00 2001 From: drake Date: Sat, 4 Jan 2025 19:19:12 -0600 Subject: [PATCH] dev and docker compose fixes --- docker-compose.yml | 14 +- package-lock.json | 607 +++++++++++++++++++++++++++++- package.json | 2 + src/app.css | 30 +- src/app.html | 13 +- src/hooks.server.ts | 11 + src/lib/db/index.ts | 8 + src/routes/+layout.svelte | 60 ++- src/routes/signin/+page.server.ts | 0 src/routes/signin/+page.svelte | 0 static/favicon.png | Bin 1571 -> 4583 bytes static/mdevtriangle.svg | 50 +++ 12 files changed, 766 insertions(+), 29 deletions(-) create mode 100644 src/hooks.server.ts create mode 100644 src/lib/db/index.ts create mode 100644 src/routes/signin/+page.server.ts create mode 100644 src/routes/signin/+page.svelte create mode 100644 static/mdevtriangle.svg diff --git a/docker-compose.yml b/docker-compose.yml index bde1d96..143063a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,17 +7,25 @@ services: environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: /run/secrets/postgres_password - ports: - - "5433:5432" volumes: - ./postgresql/data:/var/lib/postgresql/data + networks: + - fbla25 + secrets: + - postgres_password + entrypoint: [ '/bin/sh', '-c', 'export POSTGRES_PASSWORD=$$(cat /var/run/secrets/postgres_password) ; source /entrypoint.sh' ] FBLA25: image: git.marinodev.com/marinodev/fbla25_ci:latest restart: on-failure ports: - "8002:8080" + networks: + - fbla25 secrets: postgres_password: file: ./postgres/postgres_password.txt + +networks: + fbla25: + external: true diff --git a/package-lock.json b/package-lock.json index a9bfea9..4e53b95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@sveltejs/adapter-node": "^5.2.9", "@tailwindcss/forms": "^0.5.9", "autoprefixer": "^10.4.20", + "bcrypt": "^5.1.1", "js-cookie": "^3.0.5", "vitest": "^2.0.4" }, @@ -19,6 +20,7 @@ "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/kit": "^2.9.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@types/bcrypt": "^5.0.2", "eslint": "^9.7.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.36.0", @@ -732,6 +734,26 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1253,6 +1275,16 @@ "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", + "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", @@ -1272,6 +1304,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -1582,6 +1624,12 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -1613,6 +1661,18 @@ "acorn": ">=8.9.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1688,6 +1748,26 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -1771,6 +1851,20 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -1787,7 +1881,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -1944,6 +2037,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1962,6 +2064,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1981,9 +2092,14 @@ "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/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" + }, "node_modules/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", @@ -2061,6 +2177,21 @@ "node": ">=0.10.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "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", @@ -2580,6 +2711,36 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2603,6 +2764,74 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -2701,6 +2930,12 @@ "node": ">=8" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -2713,6 +2948,19 @@ "node": ">= 0.4" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2760,6 +3008,23 @@ "node": ">=0.8.19" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3020,6 +3285,30 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3067,7 +3356,6 @@ "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" @@ -3085,6 +3373,43 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -3145,12 +3470,53 @@ "dev": true, "license": "MIT" }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "license": "MIT" }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3169,6 +3535,19 @@ "node": ">=0.10.0" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3187,6 +3566,15 @@ "node": ">= 6" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -3266,6 +3654,15 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3695,6 +4092,20 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", @@ -3746,6 +4157,43 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz", @@ -3819,11 +4267,30 @@ "node": ">=6" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3832,6 +4299,12 @@ "node": ">=10" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/set-cookie-parser": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", @@ -3912,6 +4385,15 @@ "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -4336,6 +4818,32 @@ "node": ">=8.10.0" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -4427,6 +4935,12 @@ "node": ">=6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", @@ -4500,6 +5014,13 @@ } } }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "devOptional": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -5678,6 +6199,22 @@ } } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5709,6 +6246,56 @@ "node": ">=8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -5807,6 +6394,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/yaml": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", diff --git a/package.json b/package.json index 1f3e7f8..127adfc 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/kit": "^2.9.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@types/bcrypt": "^5.0.2", "eslint": "^9.7.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.36.0", @@ -36,6 +37,7 @@ "@sveltejs/adapter-node": "^5.2.9", "@tailwindcss/forms": "^0.5.9", "autoprefixer": "^10.4.20", + "bcrypt": "^5.1.1", "js-cookie": "^3.0.5", "vitest": "^2.0.4" } diff --git a/src/app.css b/src/app.css index ead4b79..e0805c8 100644 --- a/src/app.css +++ b/src/app.css @@ -3,18 +3,20 @@ @import 'tailwindcss/utilities'; [data-theme='light'] { - --text-color: #000000; - --bg-color: #f4f4f4; + --text-color: #000000; + --bg-color: #f4f4f4; + --hover-bg-color: #e4e4f0; } [data-theme='dark'] { --text-color: #f4f4f4; --bg-color: #010101; + --hover-bg-color: #1f2937; } body { - background: var(--bg-color); - color: var(--text-color); + background: var(--bg-color); + color: var(--text-color); } h1 { @@ -22,8 +24,24 @@ h1 { @apply text-4xl } -a { - @apply text-blue-500 +.nav-item { + @apply rounded px-3 py-2 text-sm mr-1 +} + +.nav-item:hover { + background-color: var(--hover-bg-color); +} + +.nav-trailing { + @apply rounded-full p-1 +} + +.nav-trailing:hover { + background-color: var(--hover-bg-color); +} + +.nav-logo:hover { + background-color: var(--hover-bg-color); } diff --git a/src/app.html b/src/app.html index 449b278..e6fe2f8 100644 --- a/src/app.html +++ b/src/app.html @@ -1,6 +1,6 @@ - + FBLA 25 @@ -9,17 +9,6 @@ %sveltekit.head% - - - - - - - - - - -
%sveltekit.body%
diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..5043762 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,11 @@ +export const handle = async ({ event, resolve }) => { + const theme = event.cookies.get('theme'); + if (!theme) { + return await resolve(event); + } + return await resolve(event, { + transformPageChunk: ({ html }) => { + return html.replace('data-theme=""', `data-theme="${theme}"`); + } + }); +}; diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts new file mode 100644 index 0000000..d38801f --- /dev/null +++ b/src/lib/db/index.ts @@ -0,0 +1,8 @@ +import bcrypt from 'bcrypt'; + +export async function createUser(username: string, password: string): Promise { + const sql = `INSERT INTO users (username, password, perms) + VALUES ($username, $password, 0)`; + + const hash = await bcrypt.hash(password, 12); +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index c52ee18..9c40de1 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,15 +1,67 @@ -
+ + +
+
+ + +
diff --git a/src/routes/signin/+page.server.ts b/src/routes/signin/+page.server.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/signin/+page.svelte b/src/routes/signin/+page.svelte new file mode 100644 index 0000000..e69de29 diff --git a/static/favicon.png b/static/favicon.png index 825b9e65af7c104cfb07089bb28659393b4f2097..04d3450f93476331af6f192ef414b8ee16a7935c 100644 GIT binary patch literal 4583 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 D9{O&# delta 1565 zcmV+&2IBeWBclwE8Gi%-003z>sXzb#00DDSM?wIu&K&6g00rGiL_t(|+U;H2ZR7!U+OIJ=AN-Q1gX#-xrWp&w_y z@)MXta?U)dS;xZ{pUV3+C2Y|J*@|1M^0HtEVPlk0_Dnt!KkXPkj3F58)>t5Za} zPWJ{u@{+FYBDs9nh1rO^E}w?y3qK3y$v6W}E>;PzkLJZ-7I9{iTo&xYYz=0W7yFQ0 z3euH%Gf^X8~_%M2E@)E5I?D7}a-=qr6=Kbg0qzZl!-c71tD&bia zsL=c?H44};bAPx?JP;+}<#6b63Ike{Fuo!?M{yEffez;|p!PfsuaC)>h>-AdbnwN1 z3g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f2%uGv?vr=KNq7YYa2Roj z;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5P#L)3xr2NyarBd`46Es|9}oU z=;TZAptAhHqfZbXeFiql%jXG?M@uk)^71VlreHvW90nF8jvjPq1ew|Ng)G0Exc5yk zaTecY1^i8)ok)27$s1jqSJ{`6t`veD9l{$?!+aqvBpkoP4B7`ax|h)*muPf46>ijz zKTmk0M}L|_!l3UBrfa?E{^*tH5}{9o=OeyqBH@)VFtID({Qf&kfrAb3DXK4-rRNmD z-~VRP-WM>zlB2;$7(o^LUy;sExKy89tX5Y6W-IT>NIN^>V*fY^C7}S?0Ct44!^wxo zVTsHjc>xN_+2N(eh+a1>W}fER{}CmOf*erj=6{5;XVF3BogH3uNl+?wxmgJ>()KCo z-}j`mqc8SBQvoV_pQHFCJYBxcQ1hG406lEb!fSLGPy82$lDGhh3Me5Wfbt3)J+g#0 z`~oag70^IJJA1`o3{*n)oDiTDP?Hq{-m2K;k1C*0s~FTos}!Mt&?vCsDhBNJa&|FO zC4XQl3-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F0Bun8U!cRB7-2ap zz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL@iUO?SBBG-0cQuo z+an4TsLy-g-+vjPe+`bX;s2dai14j32f@AJ%cKRt1jz?@ zL#U|&2Rk|USm`^&cIlJY7yzm-Xlmfy=y#0!&4E~S2*vpR^W#>)>m%0>%$Ld>rvQHc zgX^}zMo*T3P=I1AAa`^0Vt7;r6+mTFgaT;$FRP(MgCn~Cq(yy_v^Y<*&}9MTv43|y zb0`w1avZ=5-)r0x#c{elh8MoqxYmsYw8!6hGR<|nMCB;ZkqhN}jawKZA3#zd-|@wl z%5vR|P`dIciwGr4YLb}mHhfXd12i5(?YhG?J<}b)E1(l6`}HS@N90Uxh$q4BBJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6OXRY=5%C^* z26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6ROlh0MFA5h z;my}8lB0tAV-Rvc2Zs_CCVyVS^YIEviJkC##wQ4gpYZ1D8M^Avr<`+(Zr}qtfwth% z2+uEH?AbkbnS|%(7o6=Ny=21k<^*@Ogy#pl%$~27@civTy1&uy#(g>o?nW2?n^|0E zyBqv=uQes9e3Pu6&CmlZ=^Q%cGi~> P00000NkvXXu0mjf3rY84 diff --git a/static/mdevtriangle.svg b/static/mdevtriangle.svg new file mode 100644 index 0000000..418bb02 --- /dev/null +++ b/static/mdevtriangle.svg @@ -0,0 +1,50 @@ + + + + + + + + + +