From bd41cbc40d8d025218902a9f2701abf6d559bebe Mon Sep 17 00:00:00 2001 From: store <store> Date: Fri, 10 Nov 2023 10:04:46 +0100 Subject: [PATCH 01/16] bug: remove a spo join from station --- api/core/eea/dataflows.py | 3 --- api/endpoints/version/routes.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/api/core/eea/dataflows.py b/api/core/eea/dataflows.py index d7647c8..c2c768a 100644 --- a/api/core/eea/dataflows.py +++ b/api/core/eea/dataflows.py @@ -253,9 +253,6 @@ class Dataflows: ST_Z(st.geom) altitude, ST_SRID(st.geom) epsg FROM stations st - LEFT OUTER JOIN sampling_points sp ON st.id = sp.station_id - WHERE - sp.private = false GROUP BY st.id, st.name, diff --git a/api/endpoints/version/routes.py b/api/endpoints/version/routes.py index e054571..c8ad9d9 100644 --- a/api/endpoints/version/routes.py +++ b/api/endpoints/version/routes.py @@ -3,7 +3,7 @@ from flask_jwt_extended import create_access_token import requests version_endpoint = Blueprint('version', __name__) -current_version = "3.0.16" +current_version = "3.0.17" @version_endpoint.route('/api/version', methods=['GET']) -- GitLab From 5cdb89c3395fc5de0a5ccab956fad12ac2cccdb8 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 18 Jan 2024 11:36:31 +0100 Subject: [PATCH 02/16] docker and config changes --- .vscode/settings.json | 2 +- Dockerfile.api | 1 + api/config.py | 2 +- docker-compose.yml | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 85c57c0..30b4731 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "html.format.wrapLineLength": 0, - "python.formatting.autopep8Args": ["--max-line-length=20000"], + "autopep8.args": ["--max-line-length=20000"], "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.tabSize": 2, "editor.insertSpaces": true, diff --git a/Dockerfile.api b/Dockerfile.api index f6e3bac..de7784f 100644 --- a/Dockerfile.api +++ b/Dockerfile.api @@ -4,6 +4,7 @@ RUN apt -y install WORKDIR /app COPY api/requirements.txt . RUN pip install -r requirements.txt +COPY .env ../ COPY api/ ./ ENV PYTHONUNBUFFERED=1 EXPOSE 5000 diff --git a/api/config.py b/api/config.py index e8b46c6..01be3e4 100644 --- a/api/config.py +++ b/api/config.py @@ -4,7 +4,7 @@ from datetime import datetime from datetime import timedelta basedir = os.path.abspath(os.path.dirname(__file__)) -load_dotenv(os.path.join(basedir, '.env')) +load_dotenv(os.path.join(basedir, '../.env')) class Config(object): diff --git a/docker-compose.yml b/docker-compose.yml index f18ea6d..5c44242 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: sysctls: - net.ipv4.tcp_keepalive_time=200 ports: - - 5000:5000 + - ${API_PORT:-5000}:5000 client: build: context: . @@ -18,4 +18,4 @@ services: depends_on: - api ports: - - "80:80" + - ${CLIENT_PORT:-80}:80 -- GitLab From bbe64758b7945185b4995541e43882b5fce98d14 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Fri, 19 Jan 2024 14:52:28 +0100 Subject: [PATCH 03/16] added pre aggregation functionality --- README.md | 20 +- api/core/endpoints.py | 3 + .../management/preaggregation/models.py | 5 + .../management/preaggregation/routes.py | 39 + client/src/components/MenuBar.vue | 3 +- client/src/router.js | 2 + .../preaggregation/PreAggregation.vue | 54 + .../management/preaggregation/service.js | 8 + client/yarn.lock | 1250 ----------------- cron/refresh_views.py | 25 + sql/pre_aggregates.sql | 325 +++++ 11 files changed, 482 insertions(+), 1252 deletions(-) create mode 100644 api/endpoints/management/preaggregation/models.py create mode 100644 api/endpoints/management/preaggregation/routes.py create mode 100644 client/src/views/management/preaggregation/PreAggregation.vue create mode 100644 client/src/views/management/preaggregation/service.js delete mode 100644 client/yarn.lock create mode 100644 cron/refresh_views.py create mode 100644 sql/pre_aggregates.sql diff --git a/README.md b/README.md index b5b78d5..0c64b4f 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,11 @@ git clone https://git.nilu.no/raven/raven-administration ## Set environment varables -**Create a file called `.env` in the `api` folder and set the variables** +**Create a file called `.env` in the `root` folder and set the variables** ``` +API_PORT=5000 +CLIENT_PORT=80 DB_URI = postgresql://postgres:password@host:5432/database JWT_ACCESS_TOKEN_EXPIRES_SECONDS = 3600 JWT_SECRET_KEY = make-up-a-secure-key @@ -90,3 +92,19 @@ flask run # from inside the client folder start the frontend npm run dev ``` + +## Pre aggregations + +Aggregating data can be triggered manually in the raven app. +However, it is recommended to set up a schedule to trigger the aggregation on a daily basis. +The sql command that needs to run is `select raven_refresh_aggregates()` +One ways is to use the postgres extension `pgagent`. This will enable a schedular within postgres. +Another way is to set up a `cron` job in linux or a `schtasks` in windows + +The `cron` folder has a python script that can be used together with a schedular. +It does require `psycopg2-binary==2.9.5`, so make sure this is available for the scheduled task. + +```powershell +# Example of how to set up a scheduled task in Windows +schtasks /create /SC DAILY /TN raven-refresh-views /TR "<path_to_python> <path_to_raven>\cron\refresh_views.py" /ST 00:10 +``` diff --git a/api/core/endpoints.py b/api/core/endpoints.py index aa4da2b..0c05a88 100644 --- a/api/core/endpoints.py +++ b/api/core/endpoints.py @@ -66,6 +66,9 @@ class Endpoints: from endpoints.data.dataflow.routes import dataflow_endpoint app.register_blueprint(dataflow_endpoint) + from endpoints.management.preaggregation.routes import preagg_endpoint + app.register_blueprint(preagg_endpoint) + from endpoints.data.map.routes import map_endpoint app.register_blueprint(map_endpoint) diff --git a/api/endpoints/management/preaggregation/models.py b/api/endpoints/management/preaggregation/models.py new file mode 100644 index 0000000..94f649f --- /dev/null +++ b/api/endpoints/management/preaggregation/models.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + + +class AggModel(BaseModel): + type: str diff --git a/api/endpoints/management/preaggregation/routes.py b/api/endpoints/management/preaggregation/routes.py new file mode 100644 index 0000000..95df2ee --- /dev/null +++ b/api/endpoints/management/preaggregation/routes.py @@ -0,0 +1,39 @@ +from flask import jsonify, Blueprint, request +from endpoints.management.preaggregation.models import AggModel +from core.database import CursorFromPool +from core.jwt_ext_custom import jwt_required_with_management_claim +from core.query import Q +preagg_endpoint = Blueprint('preagg', __name__) + + +@preagg_endpoint.route('/api/management/preaggregation', methods=['GET']) +@jwt_required_with_management_claim() +def preagg(): + with CursorFromPool() as cursor: + sql = f""" + select 'year' as type, round(avg(cov)) as avg_cov, count(*) as count_val, count(distinct sampling_point_id) count_sp, to_char(min(time),'yyyy-mm-dd HH24:mi') as first_time, to_char(max(time),'yyyy-mm-dd HH24:mi') as last_time, to_char(max(created),'yyyy-mm-dd HH24:mi') as created from observations_year + union + select 'day' as type, round(avg(cov)) as avg_cov, count(*) as count_val, count(distinct sampling_point_id) count_sp, to_char(min(time),'yyyy-mm-dd HH24:mi') as first_time, to_char(max(time),'yyyy-mm-dd HH24:mi') as last_time, to_char(max(created),'yyyy-mm-dd HH24:mi') as created from observations_day + union + select 'winter season' as type, round(avg(cov)) as avg_cov, count(*) as count_val, count(distinct sampling_point_id) count_sp, to_char(min(time),'yyyy-mm-dd HH24:mi') as first_time, to_char(max(time),'yyyy-mm-dd HH24:mi') as last_time,to_char(max(created),'yyyy-mm-dd HH24:mi') as created from observations_winter_season + union + select 'winter year' as type, round(avg(cov)) as avg_cov, count(*) as count_val, count(distinct sampling_point_id) count_sp, to_char(min(time),'yyyy-mm-dd HH24:mi') as first_time, to_char(max(time),'yyyy-mm-dd HH24:mi') as last_time, to_char(max(created),'yyyy-mm-dd HH24:mi') as created from observations_winter_year + union + select 'summer year' as type, round(avg(cov)) as avg_cov, count(*) as count_val, count(distinct sampling_point_id) count_sp, to_char(min(time),'yyyy-mm-dd HH24:mi') as first_time, to_char(max(time),'yyyy-mm-dd HH24:mi') as last_time, to_char(max(created),'yyyy-mm-dd HH24:mi') as created from observations_summer_year + union + select 'aot40 vegetation' as type, round(avg(cov)) as avg_cov, count(*) as count_val, count(distinct sampling_point_id) count_sp, to_char(min(time),'yyyy-mm-dd HH24:mi') as first_time, to_char(max(time),'yyyy-mm-dd HH24:mi') as last_time, to_char(max(created),'yyyy-mm-dd HH24:mi') as created from observations_aot40v + union + select 'aot40 forrest' as type, round(avg(cov)) as avg_cov, count(*) as count_val, count(distinct sampling_point_id) count_sp, to_char(min(time),'yyyy-mm-dd HH24:mi') as first_time, to_char(max(time),'yyyy-mm-dd HH24:mi') as last_time, to_char(max(created),'yyyy-mm-dd HH24:mi') as created from observations_aot40f + order by type + """ + cursor.execute(sql) + values = cursor.fetchall() + return jsonify(values) + + +@preagg_endpoint.route('/api/management/preaggregation/update', methods=['GET']) +@jwt_required_with_management_claim() +def preagg_update(): + with CursorFromPool() as cursor: + cursor.execute("select raven_refresh_aggregates();") + return jsonify({'message': 'success'}) diff --git a/client/src/components/MenuBar.vue b/client/src/components/MenuBar.vue index ac30c85..3f59320 100644 --- a/client/src/components/MenuBar.vue +++ b/client/src/components/MenuBar.vue @@ -44,7 +44,8 @@ const getmodules = () => { { name: "Assessment Regimes", comp: "AssessmentRegimes", show: jwt.management && jwt.allnetworks }, { name: "Attainments", comp: "Attainments", show: jwt.management && jwt.allnetworks }, { name: "Exceedances", comp: "Exceedances", show: jwt.management && jwt.allnetworks }, - { name: "Settings", comp: "Settings", show: jwt.management && jwt.allnetworks } + { name: "Settings", comp: "Settings", show: jwt.management && jwt.allnetworks }, + { name: "Pre aggregation", comp: "PreAggregation", show: jwt.data } ] }, { diff --git a/client/src/router.js b/client/src/router.js index 034ba25..4e7e2c1 100644 --- a/client/src/router.js +++ b/client/src/router.js @@ -16,6 +16,7 @@ const AssessmentRegimes = () => import("./views/management/assessmentregimes/Ass const Attainments = () => import("./views/management/attainments/Attainments.vue"); const Exceedances = () => import("./views/management/exceedances/Exceedances.vue"); const Settings = () => import("./views/management/settings/Settings.vue"); +const PreAggregation = () => import("./views/management/preaggregation/PreAggregation.vue"); const Latest = () => import("./views/data/latest/Latest.vue"); const Historical = () => import("./views/data/historical/Historical.vue"); @@ -53,6 +54,7 @@ const routes = [ { path: "/management/attainments", component: Attainments, name: "Attainments" }, { path: "/management/exceedances", component: Exceedances, name: "Exceedances" }, { path: "/management/settings", component: Settings, name: "Settings" }, + { path: "/management/preaggregation", component: PreAggregation, name: "PreAggregation" }, { path: "/data/latest", component: Latest, name: "Latest" }, { path: "/data/historical", component: Historical, name: "Historical" }, diff --git a/client/src/views/management/preaggregation/PreAggregation.vue b/client/src/views/management/preaggregation/PreAggregation.vue new file mode 100644 index 0000000..dee582e --- /dev/null +++ b/client/src/views/management/preaggregation/PreAggregation.vue @@ -0,0 +1,54 @@ +<script setup> +import Service from "./service"; +import Eventy from "../../../helpers/eventy"; + +const data = ref([]); + +onMounted(async () => { + await loadData(); +}); + +const loadData = async () => { + data.value = await Service.get(); +}; + +const update = async () => { + Eventy.showMessage("Aggregating data. Please wait", "loading"); + await Service.update(); + await loadData(); + Eventy.hideMessage(); +}; +</script> + +<template> + <common-layout> + <tool-bar title="Pre aggregation" :show-column-picker="false" :show-add="false" :show-download="false" :show-filter="false" /> + + <container> + <div class="font-bold">Pre aggregating the data may take a while, depending on the amount of data stored in the database</div> + <div><button class="n-button" @click="update">Manually aggregate data</button></div> + </container> + <div class="mt-4"> + <table id="preaggId" class="n-table"> + <tr> + <th>Aggregation type</th> + <th>Values count</th> + <th>Samplingpoints count</th> + <th>Average coverage</th> + <!-- <th>First date</th> --> + <th>Last date</th> + <th>Last updated</th> + </tr> + <tr v-for="row in data"> + <td>{{ row.type }}</td> + <td>{{ row.count_val }}</td> + <td>{{ row.count_sp }}</td> + <td>{{ row.avg_cov ? row.avg_cov + "%" : "-" }}</td> + <!-- <td>{{ row.first_time }}</td> --> + <td>{{ row.last_time ? row.last_time : "-" }}</td> + <td class="font-bold">{{ row.created ? row.created : "-" }}</td> + </tr> + </table> + </div> + </common-layout> +</template> diff --git a/client/src/views/management/preaggregation/service.js b/client/src/views/management/preaggregation/service.js new file mode 100644 index 0000000..e304a8a --- /dev/null +++ b/client/src/views/management/preaggregation/service.js @@ -0,0 +1,8 @@ +import { Get, Post } from "../../../helpers/request"; + +const Service = { + get: async () => Get("/api/management/preaggregation"), + update: async () => Get("/api/management/preaggregation/update") +}; + +export default Service; diff --git a/client/yarn.lock b/client/yarn.lock deleted file mode 100644 index 169e87f..0000000 --- a/client/yarn.lock +++ /dev/null @@ -1,1250 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@antfu/install-pkg@^0.1.1": - "integrity" "sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==" - "resolved" "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.1.1.tgz" - "version" "0.1.1" - dependencies: - "execa" "^5.1.1" - "find-up" "^5.0.0" - -"@antfu/utils@^0.5.2": - "integrity" "sha512-CQkeV+oJxUazwjlHD0/3ZD08QWKuGQkhnrKo3e6ly5pd48VUpXbb77q0xMU4+vc2CkJnDS02Eq/M9ugyX20XZA==" - "resolved" "https://registry.npmjs.org/@antfu/utils/-/utils-0.5.2.tgz" - "version" "0.5.2" - -"@antfu/utils@^0.7.2": - "integrity" "sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==" - "resolved" "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.2.tgz" - "version" "0.7.2" - -"@babel/parser@^7.15.8", "@babel/parser@^7.16.4": - "integrity" "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" - "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz" - "version" "7.20.5" - -"@iconify/json@^2.1.147": - "integrity" "sha512-9DSzK1DIbrbjDK+LV8PTF/pTM8wJOrmRETEvVP47na093F6LEvcOQnq7Ett51e/WW0mA32GIj7LpO9opyJ/gtQ==" - "resolved" "https://registry.npmjs.org/@iconify/json/-/json-2.1.153.tgz" - "version" "2.1.153" - dependencies: - "@iconify/types" "*" - "pathe" "^0.3.0" - -"@iconify/types@*", "@iconify/types@^2.0.0": - "integrity" "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==" - "resolved" "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz" - "version" "2.0.0" - -"@iconify/utils@^2.0.3": - "integrity" "sha512-/ZYdSK+vao8XPoRPkdQeetGBtuCcPcVTtuXUz2Y+281EpcmM/5G1SCbtgty28r/Y9HkR9ePbKst7eWUOK7/jNQ==" - "resolved" "https://registry.npmjs.org/@iconify/utils/-/utils-2.0.4.tgz" - "version" "2.0.4" - dependencies: - "@antfu/install-pkg" "^0.1.1" - "@antfu/utils" "^0.5.2" - "@iconify/types" "^2.0.0" - "debug" "^4.3.4" - "kolorist" "^1.6.0" - "local-pkg" "^0.4.2" - -"@jridgewell/sourcemap-codec@^1.4.13": - "integrity" "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" - "version" "1.4.14" - -"@kurkle/color@^0.3.0": - "integrity" "sha512-hW0GwZj06z/ZFUW2Espl7toVDjghJN+EKqyXzPSV8NV89d5BYp5rRMBJoc+aUN0x5OXDMeRQHazejr2Xmqj2tw==" - "resolved" "https://registry.npmjs.org/@kurkle/color/-/color-0.3.1.tgz" - "version" "0.3.1" - -"@nodelib/fs.scandir@2.1.5": - "integrity" "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==" - "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" - "version" "2.1.5" - dependencies: - "@nodelib/fs.stat" "2.0.5" - "run-parallel" "^1.1.9" - -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": - "integrity" "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - "resolved" "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" - "version" "2.0.5" - -"@nodelib/fs.walk@^1.2.3": - "integrity" "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==" - "resolved" "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" - "version" "1.2.8" - dependencies: - "@nodelib/fs.scandir" "2.1.5" - "fastq" "^1.6.0" - -"@rollup/pluginutils@^5.0.2": - "integrity" "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==" - "resolved" "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz" - "version" "5.0.2" - dependencies: - "@types/estree" "^1.0.0" - "estree-walker" "^2.0.2" - "picomatch" "^2.3.1" - -"@types/estree@^1.0.0": - "integrity" "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" - "resolved" "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz" - "version" "1.0.0" - -"@types/web-bluetooth@^0.0.16": - "integrity" "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" - "resolved" "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz" - "version" "0.0.16" - -"@vitejs/plugin-vue@^3.2.0": - "integrity" "sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==" - "resolved" "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz" - "version" "3.2.0" - -"@vue/compiler-core@3.2.45": - "integrity" "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==" - "resolved" "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@babel/parser" "^7.16.4" - "@vue/shared" "3.2.45" - "estree-walker" "^2.0.2" - "source-map" "^0.6.1" - -"@vue/compiler-dom@3.2.45": - "integrity" "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==" - "resolved" "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@vue/compiler-core" "3.2.45" - "@vue/shared" "3.2.45" - -"@vue/compiler-sfc@^3.0.2", "@vue/compiler-sfc@3.2.45": - "integrity" "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==" - "resolved" "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@babel/parser" "^7.16.4" - "@vue/compiler-core" "3.2.45" - "@vue/compiler-dom" "3.2.45" - "@vue/compiler-ssr" "3.2.45" - "@vue/reactivity-transform" "3.2.45" - "@vue/shared" "3.2.45" - "estree-walker" "^2.0.2" - "magic-string" "^0.25.7" - "postcss" "^8.1.10" - "source-map" "^0.6.1" - -"@vue/compiler-ssr@3.2.45": - "integrity" "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==" - "resolved" "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@vue/compiler-dom" "3.2.45" - "@vue/shared" "3.2.45" - -"@vue/devtools-api@^6.4.5": - "integrity" "sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ==" - "resolved" "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.4.5.tgz" - "version" "6.4.5" - -"@vue/reactivity-transform@3.2.45": - "integrity" "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==" - "resolved" "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@babel/parser" "^7.16.4" - "@vue/compiler-core" "3.2.45" - "@vue/shared" "3.2.45" - "estree-walker" "^2.0.2" - "magic-string" "^0.25.7" - -"@vue/reactivity@3.2.45": - "integrity" "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==" - "resolved" "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@vue/shared" "3.2.45" - -"@vue/runtime-core@3.2.45": - "integrity" "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==" - "resolved" "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@vue/reactivity" "3.2.45" - "@vue/shared" "3.2.45" - -"@vue/runtime-dom@3.2.45": - "integrity" "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==" - "resolved" "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@vue/runtime-core" "3.2.45" - "@vue/shared" "3.2.45" - "csstype" "^2.6.8" - -"@vue/server-renderer@3.2.45": - "integrity" "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==" - "resolved" "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@vue/compiler-ssr" "3.2.45" - "@vue/shared" "3.2.45" - -"@vue/shared@3.2.45": - "integrity" "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==" - "resolved" "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz" - "version" "3.2.45" - -"@vueuse/core@*", "@vueuse/core@^9.6.0": - "integrity" "sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==" - "resolved" "https://registry.npmjs.org/@vueuse/core/-/core-9.6.0.tgz" - "version" "9.6.0" - dependencies: - "@types/web-bluetooth" "^0.0.16" - "@vueuse/metadata" "9.6.0" - "@vueuse/shared" "9.6.0" - "vue-demi" "*" - -"@vueuse/metadata@9.6.0": - "integrity" "sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w==" - "resolved" "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.6.0.tgz" - "version" "9.6.0" - -"@vueuse/shared@9.6.0": - "integrity" "sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==" - "resolved" "https://registry.npmjs.org/@vueuse/shared/-/shared-9.6.0.tgz" - "version" "9.6.0" - dependencies: - "vue-demi" "*" - -"acorn-node@^1.8.2": - "integrity" "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==" - "resolved" "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz" - "version" "1.8.2" - dependencies: - "acorn" "^7.0.0" - "acorn-walk" "^7.0.0" - "xtend" "^4.0.2" - -"acorn-walk@^7.0.0": - "integrity" "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" - "resolved" "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" - "version" "7.2.0" - -"acorn@^7.0.0": - "integrity" "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" - "resolved" "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" - "version" "7.4.1" - -"acorn@^8.8.1": - "integrity" "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" - "resolved" "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz" - "version" "8.8.1" - -"anymatch@~3.1.2": - "integrity" "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==" - "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" - "version" "3.1.3" - dependencies: - "normalize-path" "^3.0.0" - "picomatch" "^2.0.4" - -"arg@^5.0.2": - "integrity" "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - "resolved" "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" - "version" "5.0.2" - -"asynckit@^0.4.0": - "integrity" "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - "resolved" "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" - "version" "0.4.0" - -"autoprefixer@^10.4.13": - "integrity" "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==" - "resolved" "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz" - "version" "10.4.13" - dependencies: - "browserslist" "^4.21.4" - "caniuse-lite" "^1.0.30001426" - "fraction.js" "^4.2.0" - "normalize-range" "^0.1.2" - "picocolors" "^1.0.0" - "postcss-value-parser" "^4.2.0" - -"axios@^1.2.0": - "integrity" "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==" - "resolved" "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz" - "version" "1.2.1" - dependencies: - "follow-redirects" "^1.15.0" - "form-data" "^4.0.0" - "proxy-from-env" "^1.1.0" - -"balanced-match@^1.0.0": - "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - "version" "1.0.2" - -"binary-extensions@^2.0.0": - "integrity" "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" - "version" "2.2.0" - -"brace-expansion@^2.0.1": - "integrity" "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==" - "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" - "version" "2.0.1" - dependencies: - "balanced-match" "^1.0.0" - -"braces@^3.0.2", "braces@~3.0.2": - "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" - "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - "version" "3.0.2" - dependencies: - "fill-range" "^7.0.1" - -"browserslist@^4.21.4", "browserslist@>= 4.21.0": - "integrity" "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==" - "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" - "version" "4.21.4" - dependencies: - "caniuse-lite" "^1.0.30001400" - "electron-to-chromium" "^1.4.251" - "node-releases" "^2.0.6" - "update-browserslist-db" "^1.0.9" - -"camelcase-css@^2.0.1": - "integrity" "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" - "resolved" "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz" - "version" "2.0.1" - -"caniuse-lite@^1.0.30001400", "caniuse-lite@^1.0.30001426": - "integrity" "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==" - "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz" - "version" "1.0.30001512" - -"chart.js@^4.0.1", "chart.js@>=3.0.0", "chart.js@>=3.2.0": - "integrity" "sha512-Xta4vonV3e1pwFGLTyUMqXk2aH03D6253DSt52pdS7247u2SpIpQb6kCewxNgx1JfeLBUnjaxHYbHpOv6w78Og==" - "resolved" "https://registry.npmjs.org/chart.js/-/chart.js-4.1.0.tgz" - "version" "4.1.0" - dependencies: - "@kurkle/color" "^0.3.0" - -"chartjs-adapter-luxon@^1.3.0": - "integrity" "sha512-TPqS8S7aw4a07LhFzG5DZU6Kduk1xFkaGTn8y/gfhBRvfyCkqnwFqfXqG9Gl+gmnj5DRXgPscApJUE6bsgzKjQ==" - "resolved" "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.3.0.tgz" - "version" "1.3.0" - -"chartjs-plugin-autocolors@^0.0.7": - "integrity" "sha512-yAraaHD30d8/bXsFN/k8/Xq2cd2j8pctyd8v+mef58mEBr5RtTs1m5/3EJgB6RE+nxEOPMnZ8170siB4mmDP7g==" - "resolved" "https://registry.npmjs.org/chartjs-plugin-autocolors/-/chartjs-plugin-autocolors-0.0.7.tgz" - "version" "0.0.7" - -"chartjs-plugin-zoom@^2.0.0": - "integrity" "sha512-ogOmLu6e+Q7E1XWOCOz9YwybMslz9qNfGV2a+qjfmqJYpsw5ZMoRHZBUyW+NGhkpQ5PwwPA/+rikHpBZb7PZuA==" - "resolved" "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.0.1.tgz" - "version" "2.0.1" - dependencies: - "hammerjs" "^2.0.8" - -"chokidar@^3.5.3": - "integrity" "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==" - "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" - "version" "3.5.3" - dependencies: - "anymatch" "~3.1.2" - "braces" "~3.0.2" - "glob-parent" "~5.1.2" - "is-binary-path" "~2.1.0" - "is-glob" "~4.0.1" - "normalize-path" "~3.0.0" - "readdirp" "~3.6.0" - optionalDependencies: - "fsevents" "~2.3.2" - -"color-name@^1.1.4": - "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - "version" "1.1.4" - -"combined-stream@^1.0.8": - "integrity" "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==" - "resolved" "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" - "version" "1.0.8" - dependencies: - "delayed-stream" "~1.0.0" - -"cross-spawn@^7.0.3": - "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" - "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - "version" "7.0.3" - dependencies: - "path-key" "^3.1.0" - "shebang-command" "^2.0.0" - "which" "^2.0.1" - -"cssesc@^3.0.0": - "integrity" "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" - "resolved" "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" - "version" "3.0.0" - -"csstype@^2.6.8": - "integrity" "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" - "resolved" "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz" - "version" "2.6.21" - -"date-fns@^2.29.3": - "integrity" "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" - "resolved" "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz" - "version" "2.29.3" - -"debug@^4.3.4": - "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" - "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - "version" "4.3.4" - dependencies: - "ms" "2.1.2" - -"defined@^1.0.0": - "integrity" "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==" - "resolved" "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz" - "version" "1.0.1" - -"delayed-stream@~1.0.0": - "integrity" "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - "resolved" "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - "version" "1.0.0" - -"detective@^5.2.1": - "integrity" "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==" - "resolved" "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz" - "version" "5.2.1" - dependencies: - "acorn-node" "^1.8.2" - "defined" "^1.0.0" - "minimist" "^1.2.6" - -"didyoumean@^1.2.2": - "integrity" "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" - "resolved" "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz" - "version" "1.2.2" - -"dlv@^1.1.3": - "integrity" "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - "resolved" "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz" - "version" "1.1.3" - -"electron-to-chromium@^1.4.251": - "integrity" "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" - "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz" - "version" "1.4.284" - -"esbuild-windows-64@0.15.18": - "integrity" "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==" - "resolved" "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz" - "version" "0.15.18" - -"esbuild@^0.15.9": - "integrity" "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==" - "resolved" "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz" - "version" "0.15.18" - optionalDependencies: - "@esbuild/android-arm" "0.15.18" - "@esbuild/linux-loong64" "0.15.18" - "esbuild-android-64" "0.15.18" - "esbuild-android-arm64" "0.15.18" - "esbuild-darwin-64" "0.15.18" - "esbuild-darwin-arm64" "0.15.18" - "esbuild-freebsd-64" "0.15.18" - "esbuild-freebsd-arm64" "0.15.18" - "esbuild-linux-32" "0.15.18" - "esbuild-linux-64" "0.15.18" - "esbuild-linux-arm" "0.15.18" - "esbuild-linux-arm64" "0.15.18" - "esbuild-linux-mips64le" "0.15.18" - "esbuild-linux-ppc64le" "0.15.18" - "esbuild-linux-riscv64" "0.15.18" - "esbuild-linux-s390x" "0.15.18" - "esbuild-netbsd-64" "0.15.18" - "esbuild-openbsd-64" "0.15.18" - "esbuild-sunos-64" "0.15.18" - "esbuild-windows-32" "0.15.18" - "esbuild-windows-64" "0.15.18" - "esbuild-windows-arm64" "0.15.18" - -"escalade@^3.1.1": - "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - "version" "3.1.1" - -"escape-string-regexp@^5.0.0": - "integrity" "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" - "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz" - "version" "5.0.0" - -"estree-walker@^2.0.2": - "integrity" "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - "resolved" "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" - "version" "2.0.2" - -"execa@^5.1.1": - "integrity" "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==" - "resolved" "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" - "version" "5.1.1" - dependencies: - "cross-spawn" "^7.0.3" - "get-stream" "^6.0.0" - "human-signals" "^2.1.0" - "is-stream" "^2.0.0" - "merge-stream" "^2.0.0" - "npm-run-path" "^4.0.1" - "onetime" "^5.1.2" - "signal-exit" "^3.0.3" - "strip-final-newline" "^2.0.0" - -"fast-glob@^3.2.11", "fast-glob@^3.2.12": - "integrity" "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==" - "resolved" "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" - "version" "3.2.12" - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - "glob-parent" "^5.1.2" - "merge2" "^1.3.0" - "micromatch" "^4.0.4" - -"fastq@^1.6.0": - "integrity" "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==" - "resolved" "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz" - "version" "1.14.0" - dependencies: - "reusify" "^1.0.4" - -"fill-range@^7.0.1": - "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" - "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - "version" "7.0.1" - dependencies: - "to-regex-range" "^5.0.1" - -"find-up@^5.0.0": - "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" - "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - "version" "5.0.0" - dependencies: - "locate-path" "^6.0.0" - "path-exists" "^4.0.0" - -"follow-redirects@^1.15.0": - "integrity" "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" - "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" - "version" "1.15.2" - -"form-data@^4.0.0": - "integrity" "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==" - "resolved" "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" - "version" "4.0.0" - dependencies: - "asynckit" "^0.4.0" - "combined-stream" "^1.0.8" - "mime-types" "^2.1.12" - -"fraction.js@^4.2.0": - "integrity" "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" - "resolved" "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz" - "version" "4.2.0" - -"function-bind@^1.1.1": - "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - "version" "1.1.1" - -"get-stream@^6.0.0": - "integrity" "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - "resolved" "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" - "version" "6.0.1" - -"glob-parent@^5.1.2": - "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" - "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - "version" "5.1.2" - dependencies: - "is-glob" "^4.0.1" - -"glob-parent@^6.0.2": - "integrity" "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==" - "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" - "version" "6.0.2" - dependencies: - "is-glob" "^4.0.3" - -"glob-parent@~5.1.2": - "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" - "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - "version" "5.1.2" - dependencies: - "is-glob" "^4.0.1" - -"hammerjs@^2.0.8": - "integrity" "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==" - "resolved" "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz" - "version" "2.0.8" - -"has@^1.0.3": - "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" - "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - "version" "1.0.3" - dependencies: - "function-bind" "^1.1.1" - -"human-signals@^2.1.0": - "integrity" "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" - "resolved" "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" - "version" "2.1.0" - -"is-binary-path@~2.1.0": - "integrity" "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==" - "resolved" "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - "version" "2.1.0" - dependencies: - "binary-extensions" "^2.0.0" - -"is-core-module@^2.9.0": - "integrity" "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==" - "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz" - "version" "2.11.0" - dependencies: - "has" "^1.0.3" - -"is-extglob@^2.1.1": - "integrity" "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - "version" "2.1.1" - -"is-glob@^4.0.1", "is-glob@^4.0.3", "is-glob@~4.0.1": - "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==" - "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" - "version" "4.0.3" - dependencies: - "is-extglob" "^2.1.1" - -"is-number@^7.0.0": - "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - "version" "7.0.0" - -"is-stream@^2.0.0": - "integrity" "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" - "version" "2.0.1" - -"isexe@^2.0.0": - "integrity" "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - "version" "2.0.0" - -"js-file-download@^0.4.12": - "integrity" "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==" - "resolved" "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz" - "version" "0.4.12" - -"jsonc-parser@^3.2.0": - "integrity" "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" - "resolved" "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz" - "version" "3.2.0" - -"jwt-decode@^3.1.2": - "integrity" "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" - "resolved" "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" - "version" "3.1.2" - -"kolorist@^1.6.0": - "integrity" "sha512-dLkz37Ab97HWMx9KTes3Tbi3D1ln9fCAy2zr2YVExJasDRPGRaKcoE4fycWNtnCAJfjFqe0cnY+f8KT2JePEXQ==" - "resolved" "https://registry.npmjs.org/kolorist/-/kolorist-1.6.0.tgz" - "version" "1.6.0" - -"leaflet@^1.9.3": - "integrity" "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==" - "resolved" "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz" - "version" "1.9.3" - -"lilconfig@^2.0.5", "lilconfig@^2.0.6": - "integrity" "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==" - "resolved" "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz" - "version" "2.0.6" - -"local-pkg@^0.4.2": - "integrity" "sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==" - "resolved" "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.2.tgz" - "version" "0.4.2" - -"locate-path@^6.0.0": - "integrity" "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==" - "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - "version" "6.0.0" - dependencies: - "p-locate" "^5.0.0" - -"luxon@^3.1.1", "luxon@>=1.0.0": - "integrity" "sha512-Ah6DloGmvseB/pX1cAmjbFvyU/pKuwQMQqz7d0yvuDlVYLTs2WeDHQMpC8tGjm1da+BriHROW/OEIT/KfYg6xw==" - "resolved" "https://registry.npmjs.org/luxon/-/luxon-3.1.1.tgz" - "version" "3.1.1" - -"magic-string@^0.25.7": - "integrity" "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==" - "resolved" "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz" - "version" "0.25.9" - dependencies: - "sourcemap-codec" "^1.4.8" - -"magic-string@^0.27.0": - "integrity" "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==" - "resolved" "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz" - "version" "0.27.0" - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.13" - -"merge-stream@^2.0.0": - "integrity" "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - "resolved" "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" - "version" "2.0.0" - -"merge2@^1.3.0": - "integrity" "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - "resolved" "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" - "version" "1.4.1" - -"micromatch@^4.0.4", "micromatch@^4.0.5": - "integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==" - "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - "version" "4.0.5" - dependencies: - "braces" "^3.0.2" - "picomatch" "^2.3.1" - -"mime-db@1.52.0": - "integrity" "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" - "version" "1.52.0" - -"mime-types@^2.1.12": - "integrity" "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==" - "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" - "version" "2.1.35" - dependencies: - "mime-db" "1.52.0" - -"mimic-fn@^2.1.0": - "integrity" "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - "resolved" "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" - "version" "2.1.0" - -"minimatch@^5.1.1": - "integrity" "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==" - "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz" - "version" "5.1.1" - dependencies: - "brace-expansion" "^2.0.1" - -"minimist@^1.2.6": - "integrity" "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" - "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz" - "version" "1.2.7" - -"mitt@^3.0.0": - "integrity" "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" - "resolved" "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz" - "version" "3.0.0" - -"mlly@^1.0.0": - "integrity" "sha512-QL108Hwt+u9bXdWgOI0dhzZfACovn5Aen4Xvc8Jasd9ouRH4NjnrXEiyP3nVvJo91zPlYjVRckta0Nt2zfoR6g==" - "resolved" "https://registry.npmjs.org/mlly/-/mlly-1.0.0.tgz" - "version" "1.0.0" - dependencies: - "acorn" "^8.8.1" - "pathe" "^1.0.0" - "pkg-types" "^1.0.0" - "ufo" "^1.0.0" - -"ms@2.1.2": - "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - "version" "2.1.2" - -"nanoid@^3.3.4": - "integrity" "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" - "version" "3.3.4" - -"node-releases@^2.0.6": - "integrity" "sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==" - "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.7.tgz" - "version" "2.0.7" - -"normalize-path@^3.0.0", "normalize-path@~3.0.0": - "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - "version" "3.0.0" - -"normalize-range@^0.1.2": - "integrity" "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" - "resolved" "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" - "version" "0.1.2" - -"npm-run-path@^4.0.1": - "integrity" "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==" - "resolved" "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" - "version" "4.0.1" - dependencies: - "path-key" "^3.0.0" - -"object-hash@^3.0.0": - "integrity" "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" - "resolved" "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" - "version" "3.0.0" - -"onetime@^5.1.2": - "integrity" "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==" - "resolved" "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" - "version" "5.1.2" - dependencies: - "mimic-fn" "^2.1.0" - -"p-limit@^3.0.2": - "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" - "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - "version" "3.1.0" - dependencies: - "yocto-queue" "^0.1.0" - -"p-locate@^5.0.0": - "integrity" "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==" - "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - "version" "5.0.0" - dependencies: - "p-limit" "^3.0.2" - -"path-exists@^4.0.0": - "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - "version" "4.0.0" - -"path-key@^3.0.0", "path-key@^3.1.0": - "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - "version" "3.1.1" - -"path-parse@^1.0.7": - "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - "version" "1.0.7" - -"pathe@^0.3.0": - "integrity" "sha512-6Y6s0vT112P3jD8dGfuS6r+lpa0qqNrLyHPOwvXMnyNTQaYiwgau2DP3aNDsR13xqtGj7rrPo+jFUATpU6/s+g==" - "resolved" "https://registry.npmjs.org/pathe/-/pathe-0.3.9.tgz" - "version" "0.3.9" - -"pathe@^1.0.0": - "integrity" "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==" - "resolved" "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz" - "version" "1.0.0" - -"picocolors@^1.0.0": - "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - "version" "1.0.0" - -"picomatch@^2.0.4", "picomatch@^2.2.1", "picomatch@^2.3.1": - "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - "version" "2.3.1" - -"pify@^2.3.0": - "integrity" "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" - "resolved" "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" - "version" "2.3.0" - -"pkg-types@^1.0.0", "pkg-types@^1.0.1": - "integrity" "sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==" - "resolved" "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz" - "version" "1.0.1" - dependencies: - "jsonc-parser" "^3.2.0" - "mlly" "^1.0.0" - "pathe" "^1.0.0" - -"postcss-import@^14.1.0": - "integrity" "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==" - "resolved" "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz" - "version" "14.1.0" - dependencies: - "postcss-value-parser" "^4.0.0" - "read-cache" "^1.0.0" - "resolve" "^1.1.7" - -"postcss-js@^4.0.0": - "integrity" "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==" - "resolved" "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz" - "version" "4.0.0" - dependencies: - "camelcase-css" "^2.0.1" - -"postcss-load-config@^3.1.4": - "integrity" "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==" - "resolved" "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz" - "version" "3.1.4" - dependencies: - "lilconfig" "^2.0.5" - "yaml" "^1.10.2" - -"postcss-nested@6.0.0": - "integrity" "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==" - "resolved" "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz" - "version" "6.0.0" - dependencies: - "postcss-selector-parser" "^6.0.10" - -"postcss-selector-parser@^6.0.10": - "integrity" "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==" - "resolved" "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz" - "version" "6.0.11" - dependencies: - "cssesc" "^3.0.0" - "util-deprecate" "^1.0.2" - -"postcss-value-parser@^4.0.0", "postcss-value-parser@^4.2.0": - "integrity" "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - "resolved" "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" - "version" "4.2.0" - -"postcss@^8.0.0", "postcss@^8.1.0", "postcss@^8.1.10", "postcss@^8.2.14", "postcss@^8.3.3", "postcss@^8.4.18", "postcss@^8.4.19", "postcss@>=8.0.9": - "integrity" "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==" - "resolved" "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz" - "version" "8.4.20" - dependencies: - "nanoid" "^3.3.4" - "picocolors" "^1.0.0" - "source-map-js" "^1.0.2" - -"proxy-from-env@^1.1.0": - "integrity" "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - "resolved" "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" - "version" "1.1.0" - -"queue-microtask@^1.2.2": - "integrity" "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - "resolved" "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" - "version" "1.2.3" - -"quick-lru@^5.1.1": - "integrity" "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" - "resolved" "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" - "version" "5.1.1" - -"read-cache@^1.0.0": - "integrity" "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==" - "resolved" "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz" - "version" "1.0.0" - dependencies: - "pify" "^2.3.0" - -"readdirp@~3.6.0": - "integrity" "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==" - "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - "version" "3.6.0" - dependencies: - "picomatch" "^2.2.1" - -"resolve@^1.1.7", "resolve@^1.22.1": - "integrity" "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==" - "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" - "version" "1.22.1" - dependencies: - "is-core-module" "^2.9.0" - "path-parse" "^1.0.7" - "supports-preserve-symlinks-flag" "^1.0.0" - -"reusify@^1.0.4": - "integrity" "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - "resolved" "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" - "version" "1.0.4" - -"rollup@^1.20.0||^2.0.0||^3.0.0", "rollup@^2.79.1": - "integrity" "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==" - "resolved" "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz" - "version" "2.79.1" - optionalDependencies: - "fsevents" "~2.3.2" - -"run-parallel@^1.1.9": - "integrity" "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==" - "resolved" "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" - "version" "1.2.0" - dependencies: - "queue-microtask" "^1.2.2" - -"scule@^1.0.0": - "integrity" "sha512-4AsO/FrViE/iDNEPaAQlb77tf0csuq27EsVpy6ett584EcRTp6pTDLoGWVxCD77y5iU5FauOvhsI4o1APwPoSQ==" - "resolved" "https://registry.npmjs.org/scule/-/scule-1.0.0.tgz" - "version" "1.0.0" - -"shebang-command@^2.0.0": - "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" - "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - "version" "2.0.0" - dependencies: - "shebang-regex" "^3.0.0" - -"shebang-regex@^3.0.0": - "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - "version" "3.0.0" - -"signal-exit@^3.0.3": - "integrity" "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" - "version" "3.0.7" - -"source-map-js@^1.0.2": - "integrity" "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" - "version" "1.0.2" - -"source-map@^0.6.1": - "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - "version" "0.6.1" - -"sourcemap-codec@^1.4.8": - "integrity" "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - "resolved" "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" - "version" "1.4.8" - -"strip-final-newline@^2.0.0": - "integrity" "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" - "resolved" "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" - "version" "2.0.0" - -"strip-literal@^1.0.0": - "integrity" "sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==" - "resolved" "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.0.tgz" - "version" "1.0.0" - dependencies: - "acorn" "^8.8.1" - -"supports-preserve-symlinks-flag@^1.0.0": - "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - "version" "1.0.0" - -"tailwind-nord@^1.2.0": - "integrity" "sha512-8CsntjXDV0P+5jGhr5l5fbFPwEzxODebitSn2kQi8hW4jGYISh2WiIUkz+PRJgboaMgij9SUdI6uaWFHRNoNmw==" - "resolved" "https://registry.npmjs.org/tailwind-nord/-/tailwind-nord-1.2.0.tgz" - "version" "1.2.0" - -"tailwindcss@^3.2.4": - "integrity" "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==" - "resolved" "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz" - "version" "3.2.4" - dependencies: - "arg" "^5.0.2" - "chokidar" "^3.5.3" - "color-name" "^1.1.4" - "detective" "^5.2.1" - "didyoumean" "^1.2.2" - "dlv" "^1.1.3" - "fast-glob" "^3.2.12" - "glob-parent" "^6.0.2" - "is-glob" "^4.0.3" - "lilconfig" "^2.0.6" - "micromatch" "^4.0.5" - "normalize-path" "^3.0.0" - "object-hash" "^3.0.0" - "picocolors" "^1.0.0" - "postcss" "^8.4.18" - "postcss-import" "^14.1.0" - "postcss-js" "^4.0.0" - "postcss-load-config" "^3.1.4" - "postcss-nested" "6.0.0" - "postcss-selector-parser" "^6.0.10" - "postcss-value-parser" "^4.2.0" - "quick-lru" "^5.1.1" - "resolve" "^1.22.1" - -"to-regex-range@^5.0.1": - "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" - "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - "version" "5.0.1" - dependencies: - "is-number" "^7.0.0" - -"ufo@^1.0.0": - "integrity" "sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==" - "resolved" "https://registry.npmjs.org/ufo/-/ufo-1.0.1.tgz" - "version" "1.0.1" - -"unimport@^1.0.2": - "integrity" "sha512-DcYkDwl1XMZNmyEKUFzVzHAul0FZcj9m0OM/WRfaAtg6Gw1waYlypYJl6qAg31k57TnNPwGDCAxYPodYC5qomQ==" - "resolved" "https://registry.npmjs.org/unimport/-/unimport-1.0.2.tgz" - "version" "1.0.2" - dependencies: - "@rollup/pluginutils" "^5.0.2" - "escape-string-regexp" "^5.0.0" - "fast-glob" "^3.2.12" - "local-pkg" "^0.4.2" - "magic-string" "^0.27.0" - "mlly" "^1.0.0" - "pathe" "^1.0.0" - "pkg-types" "^1.0.1" - "scule" "^1.0.0" - "strip-literal" "^1.0.0" - "unplugin" "^1.0.1" - -"unplugin-auto-import@^0.12.0": - "integrity" "sha512-J/3ZORq5YGKG+8D5vLLOgqaHNK77izlVN07mQ752yRLqBNDbJiwPRSnUwwYqH5N6rDay1SqnJCHaUdbJ9QMI2w==" - "resolved" "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.12.1.tgz" - "version" "0.12.1" - dependencies: - "@antfu/utils" "^0.7.2" - "@rollup/pluginutils" "^5.0.2" - "local-pkg" "^0.4.2" - "magic-string" "^0.27.0" - "unimport" "^1.0.2" - "unplugin" "^1.0.1" - -"unplugin-icons@^0.14.14": - "integrity" "sha512-J6YBA+fUzVM2IZPXCK3Pnk36jYVwQ6lkjRgOnZaXNIxpMDsmwDqrE1AGJ0zUbfuEoOa90OBGc0OPfN1r+qlSIQ==" - "resolved" "https://registry.npmjs.org/unplugin-icons/-/unplugin-icons-0.14.15.tgz" - "version" "0.14.15" - dependencies: - "@antfu/install-pkg" "^0.1.1" - "@antfu/utils" "^0.7.2" - "@iconify/utils" "^2.0.3" - "debug" "^4.3.4" - "kolorist" "^1.6.0" - "local-pkg" "^0.4.2" - "unplugin" "^1.0.1" - -"unplugin-vue-components@^0.22.11": - "integrity" "sha512-FxyzsuBvMCYPIk+8cgscGBQ345tvwVu+qY5IhE++eorkyvA4Z1TiD/HCiim+Kbqozl10i4K+z+NCa2WO2jexRA==" - "resolved" "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.22.12.tgz" - "version" "0.22.12" - dependencies: - "@antfu/utils" "^0.7.2" - "@rollup/pluginutils" "^5.0.2" - "chokidar" "^3.5.3" - "debug" "^4.3.4" - "fast-glob" "^3.2.12" - "local-pkg" "^0.4.2" - "magic-string" "^0.27.0" - "minimatch" "^5.1.1" - "resolve" "^1.22.1" - "unplugin" "^1.0.1" - -"unplugin@^1.0.1": - "integrity" "sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==" - "resolved" "https://registry.npmjs.org/unplugin/-/unplugin-1.0.1.tgz" - "version" "1.0.1" - dependencies: - "acorn" "^8.8.1" - "chokidar" "^3.5.3" - "webpack-sources" "^3.2.3" - "webpack-virtual-modules" "^0.5.0" - -"update-browserslist-db@^1.0.9": - "integrity" "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==" - "resolved" "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz" - "version" "1.0.10" - dependencies: - "escalade" "^3.1.1" - "picocolors" "^1.0.0" - -"util-deprecate@^1.0.2": - "integrity" "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - "version" "1.0.2" - -"vanillajs-datepicker@^1.2.0": - "integrity" "sha512-bfGdPYMf/lPwx0bJaXKKeyr3J7TnSBzB8xRWxMq6rtLxyAyyAjdCQ1h0WRGpRmE0qXIKdDy3yzRMDLHEGOub3A==" - "resolved" "https://registry.npmjs.org/vanillajs-datepicker/-/vanillajs-datepicker-1.2.0.tgz" - "version" "1.2.0" - -"vite-plugin-fonts@^0.6.0": - "integrity" "sha512-dV6nnLEju8k5EmvlBH6egxkVZ+rgc5zWsJr9+cNRXBMEDnpRGHcZPI260UEDNg2yB99wSTNER2eduEvZFbMIGw==" - "resolved" "https://registry.npmjs.org/vite-plugin-fonts/-/vite-plugin-fonts-0.6.0.tgz" - "version" "0.6.0" - dependencies: - "fast-glob" "^3.2.11" - -"vite@^2.0.0 || ^3.0.0", "vite@^3.0.0", "vite@^3.2.4": - "integrity" "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==" - "resolved" "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz" - "version" "3.2.5" - dependencies: - "esbuild" "^0.15.9" - "postcss" "^8.4.18" - "resolve" "^1.22.1" - "rollup" "^2.79.1" - optionalDependencies: - "fsevents" "~2.3.2" - -"vue-demi@*": - "integrity" "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==" - "resolved" "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz" - "version" "0.13.11" - -"vue-router@4.1.6": - "integrity" "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==" - "resolved" "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz" - "version" "4.1.6" - dependencies: - "@vue/devtools-api" "^6.4.5" - -"vue@^3.0.0-0 || ^2.6.0", "vue@^3.2.0", "vue@^3.2.25", "vue@^3.2.45", "vue@2 || 3", "vue@3.2.45": - "integrity" "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==" - "resolved" "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz" - "version" "3.2.45" - dependencies: - "@vue/compiler-dom" "3.2.45" - "@vue/compiler-sfc" "3.2.45" - "@vue/runtime-dom" "3.2.45" - "@vue/server-renderer" "3.2.45" - "@vue/shared" "3.2.45" - -"webpack-sources@^3.2.3": - "integrity" "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" - "resolved" "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" - "version" "3.2.3" - -"webpack-virtual-modules@^0.5.0": - "integrity" "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==" - "resolved" "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz" - "version" "0.5.0" - -"which@^2.0.1": - "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" - "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - "version" "2.0.2" - dependencies: - "isexe" "^2.0.0" - -"xtend@^4.0.2": - "integrity" "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - "resolved" "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" - "version" "4.0.2" - -"yaml@^1.10.2": - "integrity" "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - "resolved" "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - "version" "1.10.2" - -"yocto-queue@^0.1.0": - "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - "version" "0.1.0" diff --git a/cron/refresh_views.py b/cron/refresh_views.py new file mode 100644 index 0000000..2e2f6cd --- /dev/null +++ b/cron/refresh_views.py @@ -0,0 +1,25 @@ +import psycopg2 +import os +from dotenv import load_dotenv + + +basedir = os.path.abspath(os.path.dirname(__file__)) +load_dotenv(os.path.join(basedir, '../.env')) + +try: + conn = psycopg2.connect(os.environ.get('DB_URI')) +except: + print("I am unable to connect to the database") + +with conn.cursor() as curs: + + try: + # Run function to refresh materialized views + print("Refreshing materialized views. This may take a while...") + curs.execute("select raven_refresh_aggregates()") + print("Done") + except (Exception, psycopg2.DatabaseError) as error: + print(error) + +conn.commit() +curs.close() diff --git a/sql/pre_aggregates.sql b/sql/pre_aggregates.sql new file mode 100644 index 0000000..912c3ff --- /dev/null +++ b/sql/pre_aggregates.sql @@ -0,0 +1,325 @@ +------------------------------------------------------------------------------------ + +create index idx_obs_spoid_day on public.observations (sampling_point_id, date_trunc('year'::text, from_time)); +create index idx_obs_spoid_day on public.observations (sampling_point_id, date_trunc('day'::text, from_time)); +VACUUM FULL ANALYZE observations; + +------------------------------------------------------------------------------------ + +create or replace function raven_coverage(datetime timestamp,count integer, timestep integer,coverage_type text default 'year') +returns numeric(10) as $$ +declare y integer; +declare is_leap_year boolean; +declare seconds integer; +begin + seconds := 31536000; + y := extract(year from datetime); + is_leap_year := (y % 4 = 0) and (y % 100 <> 0 or y % 400 = 0); + + if is_leap_year then + seconds := 31622400; + end if; + + if coverage_type = 'aot40v' then + seconds := 3974400; + elsif coverage_type = 'aot40f' then + seconds := 7905600; + elsif coverage_type = 'winterseason' and not is_leap_year then + seconds := 15724800; + elsif coverage_type = 'winterseason' and is_leap_year then + seconds := 15811200; + elsif coverage_type = 'summeryear' then + seconds := 15811200; + elsif coverage_type = 'winteryear' and not is_leap_year then + seconds := 15724800; + elsif coverage_type = 'winteryear' and is_leap_year then + seconds := 15811200; + elsif coverage_type = 'day' then + seconds := 86400; + end if; + + return round((count::numeric*100) / (seconds/timestep),10); +end +$$ language plpgsql; + + +------------------------------------------------------------------------------------ + + +create or replace function raven_refresh_aggregates() +returns void as $$ +begin + REFRESH MATERIALIZED VIEW CONCURRENTLY observations_year; + REFRESH MATERIALIZED VIEW CONCURRENTLY observations_aot40f; + REFRESH MATERIALIZED VIEW CONCURRENTLY observations_aot40v; + REFRESH MATERIALIZED VIEW CONCURRENTLY observations_winter_season; + REFRESH MATERIALIZED VIEW CONCURRENTLY observations_summer_year; + REFRESH MATERIALIZED VIEW CONCURRENTLY observations_winter_year; + REFRESH MATERIALIZED VIEW CONCURRENTLY observations_day; +end +$$ language plpgsql; + + + +------------------------------------------------------------------------------------ + +create materialized view observations_year as +with timeseries as (select s.id as sampling_point_id, t.timestep from sampling_points s, eea_times t WHERE s.timestep = t.id) +select + a.*, + raven_coverage(time,count_valid,t.timestep) as cov, + now() as created +from (select sampling_point_id, + date_trunc('year', from_time) as time, + round(avg(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as val, + round(min(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as min, + round(max(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as max, + count(value) ::int AS count_all, + count(value) FILTER (WHERE validation_flag in (1, 2, 3)) ::int AS count_valid, + count(*) FILTER (WHERE verification_flag = 1) ::int as count_verified + from observations + group by sampling_point_id, time +) a, timeseries t +where a.sampling_point_id = t.sampling_point_id; + + +CREATE INDEX idx_obs_year_id_time +on observations_year (sampling_point_id,time); + +CREATE UNIQUE INDEX un_obs_year_id_time +on observations_year (sampling_point_id,time); + +VACUUM FULL ANALYZE observations_year; + +------------------------------------------------------------------------------------ + +create materialized view observations_winter_year as +with timeseries as (select s.id as sampling_point_id, t.timestep from sampling_points s, eea_times t WHERE s.timestep = t.id) +select + a.*, + raven_coverage(a.time, a.count_valid::int,t.timestep,'winteryear') as cov, + now() as created +from ( + select + sampling_point_id, + date_trunc('year', from_time) as time, + round(avg(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as val, + round(min(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as min, + round(max(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as max, + count(value) ::int AS count_all, + count(value) FILTER (WHERE validation_flag in (1, 2, 3)) ::int AS count_valid, + count(*) FILTER (WHERE verification_flag = 1) ::int as count_verified + from observations + where 1 = 1 + and to_char(from_time, 'MM') IN ('01','02','03','10','11','12') + group by sampling_point_id, time +) a, timeseries t +where a.sampling_point_id = t.sampling_point_id; + + +CREATE INDEX idx_obs_winter_year_id_time +on observations_winter_year (sampling_point_id,time); + +CREATE UNIQUE INDEX un_obs_winter_year_id_time +on observations_winter_year (sampling_point_id,time); + +VACUUM FULL ANALYZE observations_winter_year; + +------------------------------------------------------------------------------------ + +create materialized view observations_winter_season as +with + timeseries as (select s.id as sampling_point_id, t.timestep from sampling_points s, eea_times t WHERE s.timestep = t.id), + timevalues as + (SELECT CASE EXTRACT(MONTH FROM o.from_time) + WHEN 10 THEN (o.from_time + interval '12 MONTH') + WHEN 11 THEN (o.from_time + interval '12 MONTH') + WHEN 12 THEN (o.from_time + interval '12 MONTH') + ELSE o.from_time + END as from_time, + o.sampling_point_id, + o.value, + o.validation_flag, + o.verification_flag + FROM observations o + WHERE EXTRACT(MONTH FROM o.from_time) IN (1, 2, 3, 10, 11, 12)) +select + a.*, + raven_coverage(time,count_valid,t.timestep,'winterseason') as cov, + now() as created +from ( +select + sampling_point_id, + date_trunc('year', from_time) as time, + round(avg(value) FILTER (WHERE validation_flag in (1,2,3)), 10) as val, + round(min(value) FILTER (WHERE validation_flag in (1,2,3)), 10) as min, + round(max(value) FILTER (WHERE validation_flag in (1,2,3)), 10) as max, + count(value)::int AS count_all, + count(value) FILTER (WHERE validation_flag in (1,2,3))::int AS count_valid, + count(*) FILTER (WHERE verification_flag = 1)::int as count_verified +from timevalues +group by sampling_point_id, time +) a, timeseries t +where a.sampling_point_id = t.sampling_point_id; + +CREATE INDEX idx_obs_winter_season_id_time +on observations_winter_season (sampling_point_id,time); + + +CREATE UNIQUE INDEX un_obs_winter_season_id_time +on observations_winter_season (sampling_point_id,time); + +VACUUM FULL ANALYZE observations_winter_season; + +------------------------------------------------------------------------------------ + +create materialized view observations_summer_year as +with timeseries as (select s.id as sampling_point_id, t.timestep from sampling_points s, eea_times t WHERE s.timestep = t.id) +select + a.*, + raven_coverage(a.time, a.count_valid::int,t.timestep,'summeryear') as cov, + now() as created +from ( + select + sampling_point_id, + date_trunc('year', from_time) as time, + round(avg(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as val, + round(min(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as min, + round(max(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as max, + count(value) ::int AS count_all, + count(value) FILTER (WHERE validation_flag in (1, 2, 3)) ::int AS count_valid, + count(*) FILTER (WHERE verification_flag = 1) ::int as count_verified + from observations + where 1 = 1 + and to_char(from_time, 'MM') IN ('04', '05', '06', '07', '08', '09') + group by sampling_point_id, time +) a, timeseries t +where a.sampling_point_id = t.sampling_point_id; + + +CREATE INDEX idx_obs_summer_year_id_time +on observations_summer_year(sampling_point_id,time); + +CREATE UNIQUE INDEX un_obs_summer_year_id_time +on observations_summer_year (sampling_point_id,time); + +VACUUM FULL ANALYZE observations_summer_year; + +------------------------------------------------------------------------------------ + +create materialized view observations_day as +with timeseries as (select s.id as sampling_point_id, t.timestep from sampling_points s, eea_times t WHERE s.timestep = t.id) +select + a.*, + raven_coverage(time,count_valid,t.timestep, 'day') as cov, + now() as created +from +( + select + sampling_point_id, + date_trunc('day', from_time) as time, + round(avg(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as val, + round(min(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as min, + round(max(value) FILTER (WHERE validation_flag in (1, 2, 3)), 10) as max, + count(value)::int AS count_all, + count(value) FILTER (WHERE validation_flag in (1, 2, 3)) ::int AS count_valid, + count(*) FILTER (WHERE verification_flag = 1) ::int as count_verified + from observations + group by sampling_point_id, time +) a, timeseries t +where a.sampling_point_id = t.sampling_point_id; + +CREATE INDEX idx_obs_day_id_time +on observations_day (sampling_point_id,time); + +CREATE UNIQUE INDEX un_obs_day_id_time +on observations_day (sampling_point_id,time); + +VACUUM FULL ANALYZE observations_day; + + +------------------------------------------------------------------------------------ + +create materialized view observations_aot40v as +with timeseries as (select s.id as sampling_point_id, t.timestep from sampling_points s, eea_times t WHERE s.timestep = t.id) +select + a.sampling_point_id, + a.time, + case when raven_coverage(a.time, a.count_valid,t.timestep,'aot40v') < 100 then round(a.val*count_all/count_valid,10) else a.val end as val, + a.min, + a.max, + a.count_all, + a.count_valid, + a.count_verified, + raven_coverage(a.time, a.count_valid::int,t.timestep,'aot40v') as cov, + now() as created +from ( + select + sampling_point_id, + date_trunc('year', from_time) as time, + round(sum(value - 80) FILTER (WHERE validation_flag in (1, 2, 3) AND value - 80 > 0), 10) as val, + round(min(value) FILTER (WHERE validation_flag in (1, 2, 3) AND value - 80 > 0), 10) as min, + round(max(value) FILTER (WHERE validation_flag in (1, 2, 3) AND value - 80 > 0), 10) as max, + count(value)::int AS count_all, + count(value) FILTER (WHERE validation_flag in (1, 2, 3))::int AS count_valid, + count(*) FILTER (WHERE verification_flag = 1)::int as count_verified + from observations + where 1 = 1 + and to_char(from_time, 'MM') IN ('05', '06', '07') + and to_char(from_time, 'HH24') IN ('08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19') + group by sampling_point_id, time +) a, timeseries t +where a.sampling_point_id = t.sampling_point_id; + + +CREATE INDEX idx_obs_aot40v_id_time +on observations_aot40v (sampling_point_id,time); + +CREATE UNIQUE INDEX un_obs_aot40v_id_time +on observations_aot40v (sampling_point_id,time); + +VACUUM FULL ANALYZE observations_aot40v; + +------------------------------------------------------------------------------------ + +create materialized view observations_aot40f as +with timeseries as (select s.id as sampling_point_id, t.timestep from sampling_points s, eea_times t WHERE s.timestep = t.id) +select + a.sampling_point_id, + a.time, + case when raven_coverage(a.time, a.count_valid,t.timestep,'aot40f') < 100 then round(a.val*count_all/count_valid,10) else a.val end as val, + a.min, + a.max, + a.count_all, + a.count_valid, + a.count_verified, + raven_coverage(a.time, a.count_valid::int,t.timestep,'aot40f') as cov, + now() as created +from ( + select + sampling_point_id, + date_trunc('year', from_time) as time, + round(sum(value - 80) FILTER (WHERE validation_flag in (1, 2, 3) AND value - 80 > 0), 10) as val, + round(min(value) FILTER (WHERE validation_flag in (1, 2, 3) AND value - 80 > 0), 10) as min, + round(max(value) FILTER (WHERE validation_flag in (1, 2, 3) AND value - 80 > 0), 10) as max, + count(value)::int AS count_all, + count(value) FILTER (WHERE validation_flag in (1, 2, 3))::int AS count_valid, + count(*) FILTER (WHERE verification_flag = 1)::int as count_verified + from observations + where 1 = 1 + and to_char(from_time, 'MM') IN ('04', '05', '06', '07', '08', '09') + and to_char(from_time, 'HH24') IN ('08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19') + group by sampling_point_id, time +) a, timeseries t +where a.sampling_point_id = t.sampling_point_id; + + +CREATE INDEX idx_obs_aot40f_id_time +on observations_aot40f (sampling_point_id,time); + +CREATE UNIQUE INDEX un_obs_aot40f_id_time +on observations_aot40f (sampling_point_id,time); + +VACUUM FULL ANALYZE observations_aot40f; + +------------------------------------------------------------------------------------ \ No newline at end of file -- GitLab From 6c3fb0bff799371f801b45dc88626b953a20c311 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 1 Feb 2024 11:47:12 +0100 Subject: [PATCH 04/16] windows iis userguide --- guides/windows_iis_setup.md | 107 ++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 guides/windows_iis_setup.md diff --git a/guides/windows_iis_setup.md b/guides/windows_iis_setup.md new file mode 100644 index 0000000..be88612 --- /dev/null +++ b/guides/windows_iis_setup.md @@ -0,0 +1,107 @@ +# Setup Raven on Windows and IIS + +Work in progress + +## Requirements + +- Git +- Application request routing installed and enabled + - https://www.iis.net/downloads/microsoft/application-request-routing + - https://bmscloud.no/vapcloud/help/engineeringhelp/en-us/23598993547.html + +## Setup + +### Clone repository: + +```powershell +git clone https://git.nilu.no/raven/raven-administration +``` + +### Install and build client + +Inside the client folder run these commands. +This will create a `dist` folder + +```powershell +npm install +npm build +``` + +### Create a web.config file in the `dist` folder + +Change the api port if needed + +```xml +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <system.webServer> + <rewrite> + <rules> + <rule name="backend" enabled="true" stopProcessing="true"> + <match url="^api/(.*)$" /> + <action type="Rewrite" url="http://localhost:5000/api/{R:1}"/> + </rule> + <rule name="frontend" stopProcessing="true"> + <match url="^(?!api/)(.*)" /> + <conditions logicalGrouping="MatchAll"> + <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> + <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> + </conditions> + <action type="Rewrite" url="/" /> + </rule> + </rules> + </rewrite> + </system.webServer> +</configuration> +``` + +### Install and build api + +Inside the `api`folder, create a virtual environment, activate it and istall packages + +```powershell +python -m venv venv +\venv\Scripts\activate +pip install -r requirements.txt +``` + +### Create a web.config file + +```xml +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <system.webServer> + <handlers> + <add name="raven-administration-handler" path="*" verb="*" modules="FastCgiModule" scriptProcessor="<path_to_raven>\api\venv\Scripts\python.exe|<path_to_raven>\api\venv\Lib\site-packages\wfastcgi.py" resourceType="Unspecified" /> + </handlers> + <urlCompression doStaticCompression="true" doDynamicCompression="true" /> + </system.webServer> +<appSettings> +<add key="WSGI_HANDLER" value="app.app" /> +</appSettings> +</configuration> +``` + +### Enable wfastcgi + +```powershell +pip install wfastcgi +wfastcgi-enable +``` + +### Add .env file + +``` +DB_URI = postgresql://postgres:password@host:5432/database +JWT_ACCESS_TOKEN_EXPIRES_SECONDS = 3600 +JWT_SECRET_KEY = make-up-a-secure-key +``` + +### IIS + +Setup a new website on port 80 (or use the default website) +Set the path to the `dist` folder + +Setup a new website on port 5000 +Set the path to the `api` folder +Set The applicationpool to `No managed code` -- GitLab From 05dc2e377a2b84df1003ff4e7b719f55e8c593d3 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 1 Feb 2024 11:48:42 +0100 Subject: [PATCH 05/16] spelling --- guides/windows_iis_setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/windows_iis_setup.md b/guides/windows_iis_setup.md index be88612..da700a3 100644 --- a/guides/windows_iis_setup.md +++ b/guides/windows_iis_setup.md @@ -57,7 +57,7 @@ Change the api port if needed ### Install and build api -Inside the `api`folder, create a virtual environment, activate it and istall packages +Inside the `api`folder, create a virtual environment, activate it and install packages ```powershell python -m venv venv -- GitLab From 489495683f456fa816151e0558f4dfbcda293954 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Wed, 7 Feb 2024 09:56:24 +0100 Subject: [PATCH 06/16] issue #33: set -9900 to null --- api/endpoints/qualitycontrol/validate/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/endpoints/qualitycontrol/validate/routes.py b/api/endpoints/qualitycontrol/validate/routes.py index 6a58777..a40ec34 100644 --- a/api/endpoints/qualitycontrol/validate/routes.py +++ b/api/endpoints/qualitycontrol/validate/routes.py @@ -26,7 +26,7 @@ def timevalues(): o.sampling_point_id as "sampling_point_id", o.validation_flag, o.verification_flag, - o.value::double PRECISION + case when o.value = -9900 then null else o.value::double PRECISION end as "value" FROM observations o WHERE 1=1 AND o.from_time >= %(from_dt)s -- GitLab From 0e7ee650f2fb1bcd59fccb0bee34453f506284b7 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Wed, 7 Feb 2024 10:17:56 +0100 Subject: [PATCH 07/16] bug: override width style on login container --- client/src/views/login/Login.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/views/login/Login.vue b/client/src/views/login/Login.vue index 7e0ff4f..cdcc67c 100644 --- a/client/src/views/login/Login.vue +++ b/client/src/views/login/Login.vue @@ -53,7 +53,7 @@ const reset = () => { <template> <div class="flex justify-center mt-10 w-full"> - <container class="m-auto w-80 !gap-0" v-if="!canCreateAdmin"> + <container class="m-auto !w-80 !gap-0" v-if="!canCreateAdmin"> <div class="p-2 flex flex-col"> <div class="mb-1">Username:</div> <input type="text" placeholder="Username" class="n-input w-full" v-model="username" @keyup.enter="login" /> -- GitLab From fd73a1243f7a36f92601a3185e56dd3eadb8da19 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Wed, 7 Feb 2024 11:20:10 +0100 Subject: [PATCH 08/16] bug: progressbar positionion issues --- client/src/components/ProgressBar.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/ProgressBar.vue b/client/src/components/ProgressBar.vue index 8bf157f..fd908d0 100644 --- a/client/src/components/ProgressBar.vue +++ b/client/src/components/ProgressBar.vue @@ -1,5 +1,5 @@ <template> - <div class="transition-position duration-500 ease-in-out absolute top-0 left-0 right-0 h-1 z-[999]" :class="cls"></div> + <div class="transition-position duration-500 ease-in-out absolute left-0 right-0 h-1 z-[999]" :class="cls"></div> </template> <script setup> @@ -24,7 +24,7 @@ onMounted(async () => { }); const cls = computed(() => { - var s = show.value ? "top-0" : "-top-10"; + var s = show.value ? "!top-0" : "!-top-10"; s = s + (fail.value ? " bg-nord11" : " bg-nord7 animate-pulse"); return s; }); -- GitLab From 26faaed7afda9ca18bd2f48e34c2dd24978bec97 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Wed, 7 Feb 2024 15:34:53 +0100 Subject: [PATCH 09/16] feat: allow env in api or root folder --- api/config.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/api/config.py b/api/config.py index 01be3e4..7b39b6a 100644 --- a/api/config.py +++ b/api/config.py @@ -4,7 +4,13 @@ from datetime import datetime from datetime import timedelta basedir = os.path.abspath(os.path.dirname(__file__)) -load_dotenv(os.path.join(basedir, '../.env')) + +env_in_api = os.path.isfile(os.path.join(basedir, '.env')) +env_in_root = os.path.isfile(os.path.join(basedir, '../.env')) +path = os.path.join(basedir, '.env') if env_in_api else os.path.join(basedir, '../.env') + + +load_dotenv(path) class Config(object): -- GitLab From 0fddb223c09426eae917e34a2421fe2dd1d4ac8b Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Wed, 7 Feb 2024 15:35:06 +0100 Subject: [PATCH 10/16] bug: scaling bugs --- api/core/data/processing/scaling.py | 1 + client/src/views/processing/scale/LAdd.vue | 16 +++++++++------- client/src/views/processing/scale/Scale.vue | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/api/core/data/processing/scaling.py b/api/core/data/processing/scaling.py index 7051f62..2c1c62a 100644 --- a/api/core/data/processing/scaling.py +++ b/api/core/data/processing/scaling.py @@ -98,6 +98,7 @@ class Scaling: o.validation_flag, o.import_value::DOUBLE PRECISION, o.import_value::DOUBLE PRECISION as value, + o.scaled_value::DOUBLE PRECISION, o.from_time, o.to_time, extract(epoch from o.to_time)*1000 as to_epoch, extract(epoch from o.from_time)*1000 as from_epoch diff --git a/client/src/views/processing/scale/LAdd.vue b/client/src/views/processing/scale/LAdd.vue index 210a2a3..d6f3e9a 100644 --- a/client/src/views/processing/scale/LAdd.vue +++ b/client/src/views/processing/scale/LAdd.vue @@ -4,32 +4,34 @@ const props = defineProps({ obj: Object }); -// const obj = ref({}); +const _obj = ref({}); watch( () => props.show, - () => (props.obj = {}) + () => { + _obj.value = Object.assign({}, props.obj); + } ); </script> <template> - <side-bar-crud :show="show" @cancel="$emit('close')" @commit="$emit('save', Object.assign({}, obj))"> + <side-bar-crud :show="show" @cancel="$emit('close')" @commit="$emit('save', Object.assign({}, _obj))"> <div class="mb-4 font-bold text-base border-b">Required</div> <div class="mb-2"> <div class="font-bold">Zero point:</div> - <input type="number" class="n-input w-72" v-model="obj.zero_point" placeholder="float: Zero point value" /> + <input type="number" class="n-input w-72" v-model="_obj.zero_point" placeholder="float: Zero point value" /> </div> <div class="mb-2"> <div class="font-bold">Span value:</div> - <input type="number" class="n-input w-72" v-model="obj.span_value" placeholder="float: Span value" /> + <input type="number" class="n-input w-72" v-model="_obj.span_value" placeholder="float: Span value" /> </div> <div class="mb-2"> <div class="font-bold">Gas concentration:</div> - <input type="number" class="n-input w-72" v-model="obj.gas_concentration" placeholder="float: Gas concentration" /> + <input type="number" class="n-input w-72" v-model="_obj.gas_concentration" placeholder="float: Gas concentration" /> </div> <div class="mb-2"> <div class="font-bold">Timestamp:</div> - <n-datetime v-model="obj.timestamp" class="!w-72" /> + <n-datetime v-model="_obj.timestamp" class="!w-72" /> </div> </side-bar-crud> </template> diff --git a/client/src/views/processing/scale/Scale.vue b/client/src/views/processing/scale/Scale.vue index 6c6c2d1..2676c94 100644 --- a/client/src/views/processing/scale/Scale.vue +++ b/client/src/views/processing/scale/Scale.vue @@ -87,6 +87,7 @@ const onShowAdd = () => { const onSaveAdd = async (o) => { Eventy.showMessage("Inserting scaling point. Please wait", "loading"); + console.log("onSaveAdd", o); await Service.insert(o); await onShowScalingpoints(); Eventy.showHideMessage("Scaling point added", "success", 5000); -- GitLab From ae57dbd31bb61786c44ae3215d6b8cc1125d6e65 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 8 Feb 2024 09:03:29 +0100 Subject: [PATCH 11/16] bug: set scaled value as null when rescaling --- api/core/data/processing/scaling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/core/data/processing/scaling.py b/api/core/data/processing/scaling.py index 2c1c62a..38ee5c4 100644 --- a/api/core/data/processing/scaling.py +++ b/api/core/data/processing/scaling.py @@ -98,7 +98,7 @@ class Scaling: o.validation_flag, o.import_value::DOUBLE PRECISION, o.import_value::DOUBLE PRECISION as value, - o.scaled_value::DOUBLE PRECISION, + null as scaled_value, o.from_time, o.to_time, extract(epoch from o.to_time)*1000 as to_epoch, extract(epoch from o.from_time)*1000 as from_epoch -- GitLab From b0b19ddc40948f42a2354fadc822cb5e90d8bc3a Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 8 Feb 2024 09:23:23 +0100 Subject: [PATCH 12/16] bug: do not scale -9900 value --- api/core/data/processing/scaling.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/core/data/processing/scaling.py b/api/core/data/processing/scaling.py index 38ee5c4..ee660c9 100644 --- a/api/core/data/processing/scaling.py +++ b/api/core/data/processing/scaling.py @@ -188,4 +188,6 @@ class Scaling: @staticmethod def __scalevalue__(zero, span, gas, value): + if value == -9900: + return value return (float(gas) / (float(span) - float(zero))) * (float(value) - float(zero)) -- GitLab From b9be90b791ca6d9bc1db8a05e6bd2069a70994c7 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 8 Feb 2024 09:49:48 +0100 Subject: [PATCH 13/16] add: toggle between valid only values --- .../qualitycontrol/validate/routes.py | 3 ++- .../qualitycontrol/validate/Validate.vue | 26 ++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/api/endpoints/qualitycontrol/validate/routes.py b/api/endpoints/qualitycontrol/validate/routes.py index a40ec34..37cbd9b 100644 --- a/api/endpoints/qualitycontrol/validate/routes.py +++ b/api/endpoints/qualitycontrol/validate/routes.py @@ -26,7 +26,8 @@ def timevalues(): o.sampling_point_id as "sampling_point_id", o.validation_flag, o.verification_flag, - case when o.value = -9900 then null else o.value::double PRECISION end as "value" + case when o.value = -9900 then null else o.value::double PRECISION end as "value", + case when o.validation_flag not in (1,2,3) then null else o.value::double PRECISION end as "valid_value_only" FROM observations o WHERE 1=1 AND o.from_time >= %(from_dt)s diff --git a/client/src/views/qualitycontrol/validate/Validate.vue b/client/src/views/qualitycontrol/validate/Validate.vue index 842b6f8..c0c7e71 100644 --- a/client/src/views/qualitycontrol/validate/Validate.vue +++ b/client/src/views/qualitycontrol/validate/Validate.vue @@ -16,6 +16,7 @@ import Plot from "./plot"; import IconLink from "~icons/ph/link-simple-duotone"; import Container from "../../../components/Container.vue"; +import { watch } from "vue"; const timeseries = ref([]); @@ -27,6 +28,7 @@ const timevalues = ref([]); const ev = ref({}); const showContextmenu = ref(false); const selectedRows = ref([]); +const showValidOnly = ref(false); const showPlotAndTable = ref(false); @@ -44,6 +46,13 @@ onMounted(async () => { if (route.query.ids || route.query.from || route.query.to) showData(); }); +watch( + () => showValidOnly.value, + () => { + formatAndLoad(); + } +); + const cmp_timeseries = computed(() => { return timeseries.value.filter((t) => { if (!t.fromtime && !t.totime) return true; @@ -72,6 +81,10 @@ const load = async () => { if (!chart) { chart = new Chart("chart", Plot.config(onDatapointSelection)); } + formatAndLoad(); +}; +const formatAndLoad = () => { + console.log("formatAndLoad"); chart.data = formatValues(); chart.update(); }; @@ -127,11 +140,12 @@ const formatValues = () => { let colors = []; let data = []; timevalues.value.forEach((o) => { - var v = o.value == -9900 ? null : o.value; + var value_to_use = showValidOnly.value ? o.valid_value_only : o.value; + var v = value_to_use == -9900 ? null : value_to_use; var c = o.validation_flag < 1 ? "#BF616A" : "#A3BE8C"; const n = Object.assign({}, o); colors.push(c); - data.push({ x: o.totime.replace(" ", "T"), y: o.value, obj: n }); + data.push({ x: o.totime.replace(" ", "T"), y: v, obj: n }); }); return { datasets: [Plot.dataset("Value", data, colors)] }; }; @@ -201,7 +215,13 @@ const onDatapointSelection = (event, sel, chart) => { </container> <div v-show="showPlotAndTable"> - <container class="mt-4 !p-4 h-72"><canvas id="chart"></canvas></container> + <container class="mt-4 !p-4 h-72"> + <div class="px-2 flex w-fit gap-2"> + <div class="font-bold self-center flex-1 cursor-pointer" @click="showValidOnly = !showValidOnly">Show only valid values</div> + <n-checkbox v-model="showValidOnly" class="self-center" /> + </div> + <canvas id="chart"></canvas> + </container> <div class="mt-4"> <table id="validationId" class="n-table"> -- GitLab From c028c0d2b3a3c5913a59cc99b4fc8c0e22bb517e Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 8 Feb 2024 10:00:54 +0100 Subject: [PATCH 14/16] new version --- api/endpoints/version/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/endpoints/version/routes.py b/api/endpoints/version/routes.py index c8ad9d9..6a7ccae 100644 --- a/api/endpoints/version/routes.py +++ b/api/endpoints/version/routes.py @@ -3,7 +3,7 @@ from flask_jwt_extended import create_access_token import requests version_endpoint = Blueprint('version', __name__) -current_version = "3.0.17" +current_version = "3.0.18" @version_endpoint.route('/api/version', methods=['GET']) -- GitLab From 0b7c744bc36dfd17fd956d06a84fcecaadc09dd3 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 8 Feb 2024 10:43:59 +0100 Subject: [PATCH 15/16] show imported values --- api/endpoints/qualitycontrol/validate/routes.py | 5 +++-- client/src/views/qualitycontrol/validate/Validate.vue | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/api/endpoints/qualitycontrol/validate/routes.py b/api/endpoints/qualitycontrol/validate/routes.py index 37cbd9b..2e8a4fb 100644 --- a/api/endpoints/qualitycontrol/validate/routes.py +++ b/api/endpoints/qualitycontrol/validate/routes.py @@ -26,8 +26,9 @@ def timevalues(): o.sampling_point_id as "sampling_point_id", o.validation_flag, o.verification_flag, - case when o.value = -9900 then null else o.value::double PRECISION end as "value", - case when o.validation_flag not in (1,2,3) then null else o.value::double PRECISION end as "valid_value_only" + o.value::double PRECISION , + case when o.validation_flag not in (1,2,3) then null else o.value::double PRECISION end as "valid_value_only", + o.import_value::double PRECISION FROM observations o WHERE 1=1 AND o.from_time >= %(from_dt)s diff --git a/client/src/views/qualitycontrol/validate/Validate.vue b/client/src/views/qualitycontrol/validate/Validate.vue index c0c7e71..4a5a4c4 100644 --- a/client/src/views/qualitycontrol/validate/Validate.vue +++ b/client/src/views/qualitycontrol/validate/Validate.vue @@ -215,12 +215,12 @@ const onDatapointSelection = (event, sel, chart) => { </container> <div v-show="showPlotAndTable"> - <container class="mt-4 !p-4 h-72"> + <container class="mt-4 !p-4 h-80"> <div class="px-2 flex w-fit gap-2"> <div class="font-bold self-center flex-1 cursor-pointer" @click="showValidOnly = !showValidOnly">Show only valid values</div> <n-checkbox v-model="showValidOnly" class="self-center" /> </div> - <canvas id="chart"></canvas> + <canvas id="chart" class="!h-64"></canvas> </container> <div class="mt-4"> @@ -229,6 +229,7 @@ const onDatapointSelection = (event, sel, chart) => { <th>From</th> <th>To</th> <th>Value</th> + <th>Import value</th> <th>Validation</th> <th>Verification</th> </tr> @@ -236,6 +237,7 @@ const onDatapointSelection = (event, sel, chart) => { <td>{{ row.fromtime }}</td> <td>{{ row.totime }}</td> <td>{{ row.value }}</td> + <td>{{ row.import_value }}</td> <td>{{ row.validation_flag }}</td> <td class="flex gap-1"> <div class="self-center">{{ row.verification_flag }}</div> -- GitLab From e54cc051cef12b597ec094453aa57e36e77d3b23 Mon Sep 17 00:00:00 2001 From: cst <cst@nilu.no> Date: Thu, 8 Feb 2024 10:50:44 +0100 Subject: [PATCH 16/16] removed console.logs --- client/src/views/processing/scale/Scale.vue | 1 - client/src/views/qualitycontrol/validate/Validate.vue | 1 - 2 files changed, 2 deletions(-) diff --git a/client/src/views/processing/scale/Scale.vue b/client/src/views/processing/scale/Scale.vue index 2676c94..6c6c2d1 100644 --- a/client/src/views/processing/scale/Scale.vue +++ b/client/src/views/processing/scale/Scale.vue @@ -87,7 +87,6 @@ const onShowAdd = () => { const onSaveAdd = async (o) => { Eventy.showMessage("Inserting scaling point. Please wait", "loading"); - console.log("onSaveAdd", o); await Service.insert(o); await onShowScalingpoints(); Eventy.showHideMessage("Scaling point added", "success", 5000); diff --git a/client/src/views/qualitycontrol/validate/Validate.vue b/client/src/views/qualitycontrol/validate/Validate.vue index 4a5a4c4..f6828e1 100644 --- a/client/src/views/qualitycontrol/validate/Validate.vue +++ b/client/src/views/qualitycontrol/validate/Validate.vue @@ -84,7 +84,6 @@ const load = async () => { formatAndLoad(); }; const formatAndLoad = () => { - console.log("formatAndLoad"); chart.data = formatValues(); chart.update(); }; -- GitLab