From 3e6e8c4250f78e349ca5ca2038540e1cc61959c5 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Mon, 19 Feb 2024 17:14:23 +0100 Subject: [PATCH 01/84] local files, nginx --- .envs/.local/.django | 5 +++ .gitignore | 7 +++- compose/local/dask/Dockerfile | 5 +++ compose/local/django/Dockerfile | 4 ++- compose/local/django/start | 2 +- compose/local/nginx/default.conf | 40 +++++++++++++++++++++ config/settings/base.py | 9 +++-- docker-compose.yml | 54 +++++++++++++++++++++++++---- orochi/templates/website/index.html | 18 +++++++++- orochi/utils/volatility_dask_elk.py | 8 +++-- orochi/website/forms.py | 16 ++++++--- orochi/website/views.py | 27 +++++++++++---- requirements/base.txt | 3 ++ 13 files changed, 172 insertions(+), 26 deletions(-) create mode 100644 compose/local/nginx/default.conf diff --git a/.envs/.local/.django b/.envs/.local/.django index b42718e1..666c960b 100755 --- a/.envs/.local/.django +++ b/.envs/.local/.django @@ -29,6 +29,11 @@ AWESOME_PATH=https://raw.githubusercontent.com/InQuest/awesome-yara/master/READM LOCAL_YARA_PATH=/yara DEFAULT_YARA_RULE_PATH=/yara/default.yara VOLATILITY_SYMBOL_DOWNLOAD_PATH=https://downloads.volatilityfoundation.org/volatility3/symbols +LOCAL_UPLOAD_PATH=/uploads + +# Debug +# ------------------------------------------------------------------------------ +DEBUG_LEVEL=WARNING # Ldap # ------------------------------------------------------------------------------ diff --git a/.gitignore b/.gitignore index 21d1c867..14235ea5 100644 --- a/.gitignore +++ b/.gitignore @@ -271,7 +271,12 @@ compose/local/clamav/freshclam.conf # History .history + +# Temporary test files orochi/utils/test.py +docker-compose__tmp.yml + +# Maxmind compose/local/maxmind/GeoLite2-ASN.mmdb compose/local/maxmind/GeoLite2-City.mmdb -compose/local/maxmind/GeoLite2-Country.mmdb \ No newline at end of file +compose/local/maxmind/GeoLite2-Country.mmdb diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index e1e74f4e..283483ae 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,6 +1,8 @@ FROM daskdev/dask:2024.1.1-py3.11 ENV DEBIAN_FRONTEND noninteractive +ARG local_folder=/uploads + RUN apt-get --allow-releaseinfo-change update \ # dependencies for building Python packages && apt-get install -y --no-install-recommends build-essential \ @@ -53,6 +55,9 @@ RUN chmod +x /usr/bin/prepare.sh COPY ./compose/local/dask/daskworkerinit.py /opt/daskworkerinit.py COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py +RUN mkdir -p $local_folder /maxmind +COPY ./compose/local/maxmind /maxmind + WORKDIR /app COPY . . ENV PYTHONPATH "${PYTHONPATH}:/app" diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 485c6051..791d4ea5 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -4,6 +4,8 @@ ENV DJANGO_SETTINGS_MODULE config.settings.local ENV PYTHONUNBUFFERED 1 ENV PYTHONDONTWRITEBYTECODE 1 +ARG local_folder=/uploads + RUN apt-get update \ # dependencies for building Python packages && apt-get install -y --no-install-recommends build-essential \ @@ -69,7 +71,7 @@ RUN pip install -r /requirements/local.txt --ignore-installed ruamel.yaml COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py -RUN mkdir /maxmind +RUN mkdir -p $local_folder /maxmind COPY ./compose/local/maxmind /maxmind WORKDIR /app diff --git a/compose/local/django/start b/compose/local/django/start index 9264c353..ee6bcbfd 100644 --- a/compose/local/django/start +++ b/compose/local/django/start @@ -7,4 +7,4 @@ set -o nounset python manage.py makemigrations python manage.py migrate python manage.py collectstatic --skip-checks --noinput --clear -daphne -b 0.0.0.0 -p 8000 config.asgi:application +gunicorn config.wsgi:application --workers=2 -b :8000 diff --git a/compose/local/nginx/default.conf b/compose/local/nginx/default.conf new file mode 100644 index 00000000..ca7311f4 --- /dev/null +++ b/compose/local/nginx/default.conf @@ -0,0 +1,40 @@ +upstream django_wsgi { + server django_wsgi:8000; +} + +upstream django_asgi { + server django_asgi:9000; +} + +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 80 default_server; + + location = /favicon.ico { access_log off; log_not_found off; } + + location / { + proxy_pass http://django_wsgi; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_redirect off; + + client_max_body_size 20M; + } + + location /ws/notify/ { + proxy_pass http://django_asgi; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } +} diff --git a/config/settings/base.py b/config/settings/base.py index ee858f83..a47917a0 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -228,6 +228,7 @@ # LOGGING # ------------------------------------------------------------------------------ +DEBUG_LEVEL = env("DEBUG_LEVEL", default="WARNING") LOGGING = { "version": 1, "disable_existing_loggers": False, @@ -239,14 +240,14 @@ }, "handlers": { "console": { - "level": "INFO", + "level": DEBUG_LEVEL, "class": "logging.StreamHandler", "formatter": "verbose", } }, - "root": {"level": "INFO", "handlers": ["console"]}, + "root": {"level": DEBUG_LEVEL, "handlers": ["console"]}, "loggers": { - "distributed": {"level": "INFO", "handlers": ["console"]}, + "distributed": {"level": DEBUG_LEVEL, "handlers": ["console"]}, }, } @@ -334,3 +335,5 @@ DWARF2JSON = "/dwarf2json/./dwarf2json" # online path of volatility symbols VOLATILITY_SYMBOL_DOWNLOAD_PATH = env("VOLATILITY_SYMBOL_DOWNLOAD_PATH") +# path of a remote folder with already uploaded files +LOCAL_UPLOAD_PATH = env("LOCAL_UPLOAD_PATH") diff --git a/docker-compose.yml b/docker-compose.yml index 2608ec48..f9cadc3a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,15 +13,27 @@ volumes: services: - django: &django + nginx: + image: nginx:1.15.0 + container_name: orochi_nginx + depends_on: + - django_asgi + - django_wsgi + volumes: + - ./compose/local/nginx:/etc/nginx/conf.d + ports: + - "80:80" + + django_wsgi: build: context: . dockerfile: ./compose/local/django/Dockerfile args: - http_proxy - https_proxy + - local_upload_path image: ghcr.io/ldo-cert/orochi_django:latest - container_name: orochi_django + container_name: orochi_django_wsgi hostname: django restart: always depends_on: @@ -39,15 +51,43 @@ services: environment: - http_proxy=${http_proxy} - https_proxy=${https_proxy} - ports: - - "8000:8000" + expose: + - 8000 command: /start - postgres: + django_asgi: build: context: . - dockerfile: ./compose/local/postgres/Dockerfile - image: ghcr.io/ldo-cert/orochi_postgres:latest + dockerfile: ./compose/local/django/Dockerfile + args: + - http_proxy + - https_proxy + - local_upload_path + image: ghcr.io/ldo-cert/orochi_django:latest + container_name: orochi_django_asgi + hostname: django + restart: always + depends_on: + - postgres + - mailhog + volumes: + - media_path:/media + - symbols_path:/src/volatility3/volatility3/symbols + - plugin_path:/src/volatility3/volatility3/framework/plugins/custom + - yara_path:/yara + - cache_path:/root/.cache/volatility3 + env_file: + - ./.envs/.local/.django + - ./.envs/.local/.postgres + environment: + - http_proxy=${http_proxy} + - https_proxy=${https_proxy} + expose: + - 9000 + command: daphne -b 0.0.0.0 -p 9000 config.asgi:application + + postgres: + image: postgres:16.2 container_name: orochi_postgres hostname: postgres restart: always diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index 887b254b..e75d5f7a 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -449,6 +449,8 @@
History Log
callbacks: { onSuccess: upload => { $("#btn_create_index").removeClass('disabled'); + // upload file clear local folder value + $("#id_local_folder").val(''); } } } @@ -458,6 +460,20 @@
History Log
}); }); + $(document).on("change", "#id_local_folder", function () { + var value = $(this).val(); + if (value != "") { + $("#id_file").val(''); + $("#id_upload").prop('disabled', true); + $("#btn_create_index").removeClass('disabled'); + $("#id_mode").val('folder'); + }else{ + $("#id_upload").prop('disabled', false); + $("#btn_create_index").addClass('disabled'); + $("#id_mode").val('upload'); + } + }); + // ADD INDEX FORM SUBMIT $(document).on("submit", "#create-index", function (e) { e.preventDefault(); @@ -690,7 +706,7 @@
History Log
method: 'get', dataType: 'json', success: function (data) { - btn.parent().parent().remove(); + btn.parent().parent().parent().remove(); // REMOVE INDEX FROM SELECTED LIST selected_indexes = selected_indexes.filter(function (item) { return item !== index; diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index b3022234..74fe76c2 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -783,7 +783,7 @@ def refresh_symbols(): logging.debug(f"[Refresh Symbol Cache] Completed") -def unzip_then_run(dump_pk, user_pk, password, restart): +def unzip_then_run(dump_pk, user_pk, password, restart, move): try: dump = Dump.objects.get(pk=dump_pk) logging.debug(f"[dump {dump_pk}] Processing") @@ -791,7 +791,11 @@ def unzip_then_run(dump_pk, user_pk, password, restart): if not restart: # COPY EACH FILE IN THEIR FOLDER BEFORE UNZIP/RUN PLUGIN extract_path = f"{settings.MEDIA_ROOT}/{dump.index}" - filepath = shutil.move(dump.upload.path, extract_path) + if move: + filepath = shutil.move(dump.upload.path, extract_path) + else: + # filepath = shutil.copy(dump.upload.path, extract_path) + filepath = dump.upload.path filetype = magic.from_file(filepath, mime=True) if filetype in [ diff --git a/orochi/website/forms.py b/orochi/website/forms.py index c348b081..c3c1da28 100644 --- a/orochi/website/forms.py +++ b/orochi/website/forms.py @@ -1,8 +1,7 @@ from datetime import datetime from django import forms -from django.contrib.admin import site as admin_site -from django.contrib.admin.widgets import RelatedFieldWidgetWrapper +from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.postgres.forms import SimpleArrayField from django.forms.widgets import CheckboxInput @@ -13,7 +12,7 @@ ) from orochi.utils.plugin_install import plugin_install -from orochi.website.models import OPERATING_SYSTEM, Bookmark, Dump, Folder, Plugin +from orochi.website.models import Bookmark, Dump, Folder, Plugin ###################################### @@ -60,19 +59,25 @@ class Meta: # DUMPS ###################################### class DumpForm(FileFormMixin, forms.ModelForm): - upload = UploadedFileField() + upload = UploadedFileField(required=False) password = forms.CharField(required=False) + local_folder = forms.FilePathField( + path=settings.LOCAL_UPLOAD_PATH, required=False, recursive=True + ) + mode = forms.CharField(widget=forms.HiddenInput(), required=False, initial="upload") class Meta: model = Dump fields = ( "upload", + "local_folder", "name", "folder", "operating_system", "comment", "password", "color", + "mode", ) def __init__(self, current_user, *args, **kwargs): @@ -80,6 +85,9 @@ def __init__(self, current_user, *args, **kwargs): self.fields["folder"] = forms.ModelChoiceField( queryset=Folder.objects.filter(user=current_user), required=False ) + self.fields["local_folder"] = forms.FilePathField( + path=settings.LOCAL_UPLOAD_PATH, required=False, recursive=True + ) class EditDumpForm(forms.ModelForm): diff --git a/orochi/website/views.py b/orochi/website/views.py index c2135785..54e21f91 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -1153,11 +1153,11 @@ def edit(request): return JsonResponse(data) -def index_f_and_f(dump_pk, user_pk, password=None, restart=None): +def index_f_and_f(dump_pk, user_pk, password=None, restart=None, move=True): """Run all plugin for a new index on dask""" dask_client = Client(settings.DASK_SCHEDULER_URL) fire_and_forget( - dask_client.submit(unzip_then_run, dump_pk, user_pk, password, restart) + dask_client.submit(unzip_then_run, dump_pk, user_pk, password, restart, move) ) @@ -1170,14 +1170,28 @@ def create(request): form = DumpForm(current_user=request.user, data=request.POST) if form.is_valid(): with transaction.atomic(): - upload = form.cleaned_data["upload"] + mode = form.cleaned_data["mode"] + dump_index = str(uuid.uuid1()) + os.mkdir(f"{settings.MEDIA_ROOT}/{dump_index}") + dump = form.save(commit=False) + if mode == "upload": + dump.upload = form.cleaned_data["upload"] + move = True + else: + filename = os.path.basename(form.cleaned_data["local_folder"]) + shutil.move( + form.cleaned_data["local_folder"], + f"{settings.MEDIA_ROOT}/{dump_index}", + ) + dump.upload.name = f"{settings.MEDIA_URL}{dump_index}/{filename}" + move = False dump.author = request.user - dump.upload = upload - dump.index = str(uuid.uuid1()) + + dump.index = dump_index dump.save() form.delete_temporary_files() - os.mkdir(f"{settings.MEDIA_ROOT}/{dump.index}") + data["form_is_valid"] = True # for each plugin enabled and for that os I create a result @@ -1210,6 +1224,7 @@ def create(request): request.user.pk, password=form.cleaned_data["password"], restart=None, + move=move, ) ) diff --git a/requirements/base.txt b/requirements/base.txt index a09bde86..585b23bd 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -33,6 +33,9 @@ django-allauth==0.60.1 django-crispy-forms==2.1 # https://github.com/jazzband/django-redis django-redis==5.4.0 +# https://gunicorn.org/ +gunicorn==21.2.0 + # Django Rest Framework # ------------------------------------------------------------------------------ From 9d7f31c939c48ae6d7598cd4f1526844143dc6dd Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 20 Feb 2024 11:29:28 +0100 Subject: [PATCH 02/84] empty clamav with - --- CHANGELOG.md | 10 +++++++++- orochi/utils/volatility_dask_elk.py | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e9b1308..11085795 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,18 @@ ## Changelog -
OROCHI 2.2.0 + * Upload ntoskrnl.exe and generate symbol [[#1020](https://github.com/LDO-CERT/orochi/issues/1020)] + * evaluate possibility to switch from daphne to uvicorn for asgi [[#982](https://github.com/LDO-CERT/orochi/issues/982)] + * Improve path flexibility for local import (non-GUI dump uploads [[#451](https://github.com/LDO-CERT/orochi/issues/451)] +
+ +
+ OROCHI 2.1.1 [2024/02/13] + * ADD more info on foreign addr in netstat [[#494](https://github.com/LDO-CERT/orochi/issues/494)] + * Expand/Collapse folders [[#1006](https://github.com/LDO-CERT/orochi/issues/1006)]
diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index 74fe76c2..6a6ae2ba 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -538,7 +538,7 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None): for res in match if str(res.path) == down_path ), - None, + "-", ) es = Elasticsearch( From 1afbfd532957c038729ef6389c4644038b503683 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 20 Feb 2024 16:01:34 +0100 Subject: [PATCH 03/84] api test code --- compose/local/nginx/default.conf | 2 +- examples/local_api.ipynb | 150 ++++++++++++++++++++++++++++++ orochi/website/api/serializers.py | 2 +- orochi/website/api/views.py | 31 +++--- 4 files changed, 164 insertions(+), 21 deletions(-) create mode 100644 examples/local_api.ipynb diff --git a/compose/local/nginx/default.conf b/compose/local/nginx/default.conf index ca7311f4..1f799bff 100644 --- a/compose/local/nginx/default.conf +++ b/compose/local/nginx/default.conf @@ -22,7 +22,7 @@ server { proxy_set_header Host $host; proxy_redirect off; - client_max_body_size 20M; + client_max_body_size 1000M; } location /ws/notify/ { diff --git a/examples/local_api.ipynb b/examples/local_api.ipynb new file mode 100644 index 00000000..f250d324 --- /dev/null +++ b/examples/local_api.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import getpass\n", + "from requests import Session\n", + "from pprint import pprint\n", + "\n", + "url = \"http://127.0.0.1\"\n", + "user = input()\n", + "password = getpass.getpass()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# LOGIN" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "session = Session()\n", + "req = session.post(\n", + " f\"{url}/auth-token/\", \n", + " data={\"username\": user, \"password\": password}\n", + ")\n", + "if req.status_code != 200:\n", + " print(req.json())\n", + " exit(1)\n", + "token = req.json()[\"token\"]\n", + "session.headers[\"Authorization\"] = f\"Token {token}\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GET DUMP LIST" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dumps = session.get(f\"{url}/api/dumps/\").json()\n", + "print(f\"{len(dumps)} dumps found\")\n", + "pprint(dumps[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CREATE DUMP" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "files = {'upload': open('/home/DATA/AMF_MemorySamples/linux/sorpresa.zip','rb')}\n", + "values = {'operating_system': 'Linux', 'name': '333'}\n", + "res = session.post(f\"{url}/api/dumps/\", files=files, data=values)\n", + "if res.status_code == 200:\n", + " pprint(res.json())\n", + "else:\n", + " print(res.status_code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CREATE DUMP FROM REMOTE DUMP" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This code requires a file on the server in the folder specified in the LOCAL_UPLOAD_PATH\n", + "# settings folder\n", + "\n", + "res = session.post(f\"{url}/api/dumps/import_local/\", files=(\n", + " ('operating_system', (None, 'Linux')),\n", + " ('name', (None, 'sasf3sfas33')),\n", + " ('filepath', (None, '/uploads/linux/linux-sample-4.bin')),\n", + " ))\n", + "if res.status_code == 200:\n", + " pprint(res.json())\n", + "else:\n", + " print(res.status_code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GET PLUGIN LIST" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plugins = session.get(f\"{url}/api/plugin/\").json()\n", + "print(f\"{len(plugins)} plugins found\")\n", + "pprint(plugins[0])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "orochi", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/orochi/website/api/serializers.py b/orochi/website/api/serializers.py index 9f6ee701..1a1f5bc7 100644 --- a/orochi/website/api/serializers.py +++ b/orochi/website/api/serializers.py @@ -9,7 +9,7 @@ class ImportLocalSerializer(serializers.Serializer): filepath = serializers.FilePathField( - path="{}/uploads".format(settings.MEDIA_ROOT), recursive=True + path=settings.LOCAL_UPLOAD_PATH, recursive=True ) name = serializers.CharField() operating_system = serializers.ChoiceField(choices=["Linux", "Mac", "Windows"]) diff --git a/orochi/website/api/views.py b/orochi/website/api/views.py index 9dc2f8a8..dbaefbdb 100644 --- a/orochi/website/api/views.py +++ b/orochi/website/api/views.py @@ -24,7 +24,6 @@ from orochi.website.api.permissions import ( AuthAndAuthorized, - GrandParentAuthAndAuthorized, NotUpdateAndIsAuthenticated, ParentAuthAndAuthorized, ) @@ -132,7 +131,7 @@ def create(self, request, *args, **kwargs): lambda: index_f_and_f( dump.pk, request.user.pk, - password=serializer.validated_data["password"], + password=serializer.validated_data.get("password"), restart=None, ) ) @@ -148,10 +147,11 @@ def create(self, request, *args, **kwargs): @action(detail=False, methods=["post"], serializer_class=ImportLocalSerializer) def import_local(self, request): - local_path = Path(request.data["filepath"]) - media_path = f"{settings.MEDIA_ROOT}/uploads" + dump_index = str(uuid.uuid1()) + os.mkdir(f"{settings.MEDIA_ROOT}/{dump_index}") - uploaded_name = f"{media_path}/{local_path.name}" + local_path = Path(request.data["filepath"]) + filename = local_path.name if not local_path.exists(): return Response( @@ -159,17 +159,10 @@ def import_local(self, request): status=status.HTTP_400_BAD_REQUEST, ) - if Path(settings.MEDIA_ROOT) not in Path(local_path).parents: - return Response( - {"Error": "Filepath must be under MEDIA PATH!"}, - status=status.HTTP_400_BAD_REQUEST, - ) - - # IF ALREADY UNDER RIGHT FOLDER OK, ELSE MOVE IT - if local_path.parent.absolute() == media_path: - uploaded_name = local_path - else: - local_path.rename(uploaded_name) + shutil.copy( + str(local_path), + f"{settings.MEDIA_ROOT}/{dump_index}", + ) operating_system = request.data["operating_system"] operating_system = operating_system.capitalize() @@ -184,11 +177,11 @@ def import_local(self, request): with transaction.atomic(): dump = Dump( author=request.user, - index=str(uuid.uuid1()), + index=dump_index, name=name, operating_system=operating_system, ) - dump.upload.name = str(uploaded_name) + dump.upload.name = f"{settings.MEDIA_URL}{dump_index}/{filename}" dump.save() Result.objects.bulk_create( [ @@ -215,7 +208,7 @@ def import_local(self, request): lambda: index_f_and_f( dump.pk, request.user.pk, - password=request.data["password"], + password=request.data.get("password"), restart=None, ) ) From 485c4abe211e9d160ab041d2cd5000037a0d2d87 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 20 Feb 2024 16:43:15 +0100 Subject: [PATCH 04/84] api test code --- examples/local_api.ipynb | 62 +++++++++++++++++++++++++++++++ orochi/website/api/serializers.py | 11 +----- orochi/website/api/views.py | 3 +- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/examples/local_api.ipynb b/examples/local_api.ipynb index f250d324..676501ba 100644 --- a/examples/local_api.ipynb +++ b/examples/local_api.ipynb @@ -124,6 +124,68 @@ "print(f\"{len(plugins)} plugins found\")\n", "pprint(plugins[0])" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GET PLUGIN STATUS ON SELECTED DUMP" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res = session.get(f\"{url}/api/dumps/{dump_pk}/results/\")\n", + "if res.status_code == 200:\n", + " pprint(res.json())\n", + "else:\n", + " print(res.status_code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# RESUBMIT PLUGIN" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "res = session.post(f\"{url}/api/dumps/{dump_pk}/results/{result_pk}/resubmit/\", data={'parameter': {'dump': True}})\n", + "if res.status_code == 200:\n", + " pprint(res.json())\n", + "else:\n", + " print(res.status_code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SHOW PLUGIN RESULT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dump_pk = 27\n", + "result_pk = 624\n", + "res = session.get(f\"{url}/api/dumps/{dump_pk}/results/{result_pk}/result\")\n", + "if res.status_code == 200:\n", + " pprint(res.json())\n", + "else:\n", + " print(res.status_code)" + ] } ], "metadata": { diff --git a/orochi/website/api/serializers.py b/orochi/website/api/serializers.py index 1a1f5bc7..cc0c0356 100644 --- a/orochi/website/api/serializers.py +++ b/orochi/website/api/serializers.py @@ -52,7 +52,6 @@ class ResultSerializer(serializers.ModelSerializer): status = serializers.SerializerMethodField() result = serializers.SerializerMethodField("result_url") resubmit = serializers.SerializerMethodField("resubmit_url") - extracted_dumps = serializers.SerializerMethodField("extracted_dumps_url") def get_status(self, obj): return obj.get_result_display() @@ -73,14 +72,6 @@ def resubmit_url(self, obj): .replace("result/", "") ) - def extracted_dumps_url(self, obj): - return "{}ext-dumps/".format( - self.context["request"] - .build_absolute_uri() - .replace("resubmit/", "") - .replace("result/", "") - ) - class Meta: model = Result read_only_fields = ("description",) @@ -92,7 +83,6 @@ class Meta: "updated_at", "result", "resubmit", - "extracted_dumps", ] @@ -160,6 +150,7 @@ def get_status(self, obj): class Meta: model = Dump fields = [ + "index", "operating_system", "author", "name", diff --git a/orochi/website/api/views.py b/orochi/website/api/views.py index dbaefbdb..4f25fdec 100644 --- a/orochi/website/api/views.py +++ b/orochi/website/api/views.py @@ -210,6 +210,7 @@ def import_local(self, request): request.user.pk, password=request.data.get("password"), restart=None, + move=False, ) ) @@ -248,7 +249,7 @@ def resubmit(self, request, pk=None, dump_pk=None): # REMOVE OLD DATA es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) es_client.indices.delete( - f"{dump.index}_{plugin.name.lower()}", ignore=[400, 404] + index=f"{dump.index}_{plugin.name.lower()}", ignore=[400, 404] ) transaction.on_commit( From 3d925d9ee33a35dfc631237e691787c245cc7ef8 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 21 Feb 2024 09:23:59 +0100 Subject: [PATCH 05/84] vt/maxmind error, update notebook --- examples/local_api.ipynb | 60 +++++++++++++++++++--- orochi/templates/website/partial_json.html | 7 +++ orochi/website/views.py | 14 +++-- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/examples/local_api.ipynb b/examples/local_api.ipynb index 676501ba..2426adaa 100644 --- a/examples/local_api.ipynb +++ b/examples/local_api.ipynb @@ -72,10 +72,11 @@ "outputs": [], "source": [ "files = {'upload': open('/home/DATA/AMF_MemorySamples/linux/sorpresa.zip','rb')}\n", - "values = {'operating_system': 'Linux', 'name': '333'}\n", + "values = {'operating_system': 'Linux', 'name': 'sorpresa'}\n", "res = session.post(f\"{url}/api/dumps/\", files=files, data=values)\n", "if res.status_code == 200:\n", " pprint(res.json())\n", + " dump_pk = res.json()[\"pk\"]\n", "else:\n", " print(res.status_code)" ] @@ -120,9 +121,11 @@ "metadata": {}, "outputs": [], "source": [ - "plugins = session.get(f\"{url}/api/plugin/\").json()\n", - "print(f\"{len(plugins)} plugins found\")\n", - "pprint(plugins[0])" + "res = session.get(f\"{url}/api/plugin/\")\n", + "if res.status_code == 200:\n", + " plugins = res.json()\n", + " print(f\"{len(plugins)} plugins found\")\n", + " pprint(plugins[0])" ] }, { @@ -141,7 +144,7 @@ "res = session.get(f\"{url}/api/dumps/{dump_pk}/results/\")\n", "if res.status_code == 200:\n", " pprint(res.json())\n", - "else:\n", + " result_pk = [x['pk'] for x in res.json() if x['plugin'] == 'linux.pslist.PsList'][0]\n", " print(res.status_code)" ] }, @@ -165,6 +168,30 @@ " print(res.status_code)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CHECK PLUGIN STATUS" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "status = 'Running'\n", + "while status != 'Success':\n", + " res = session.get(f\"{url}/api/dumps/{dump_pk}/results/{result_pk}/\")\n", + " if res.status_code == 200:\n", + " status = res.json()['status']\n", + " pprint(status)\n", + " else:\n", + " print(res.status_code)\n", + " break" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -178,14 +205,31 @@ "metadata": {}, "outputs": [], "source": [ - "dump_pk = 27\n", - "result_pk = 624\n", "res = session.get(f\"{url}/api/dumps/{dump_pk}/results/{result_pk}/result\")\n", "if res.status_code == 200:\n", - " pprint(res.json())\n", + " pprint(len(res.json()))\n", "else:\n", " print(res.status_code)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# WORK WITH RETURNED DATA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import pygwalker as pyg\n", + "df = pd.DataFrame.from_records(res.json())\n", + "walker = pyg.walk(df)" + ] } ], "metadata": { diff --git a/orochi/templates/website/partial_json.html b/orochi/templates/website/partial_json.html index 7646a2c8..7a20e319 100644 --- a/orochi/templates/website/partial_json.html +++ b/orochi/templates/website/partial_json.html @@ -4,7 +4,14 @@
From 1e95539b34519a0ef09965bea00febe1d9653ee8 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 22 Feb 2024 22:02:40 +0100 Subject: [PATCH 09/84] test build --- version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.py b/version.py index 0309ae29..8a124bf6 100644 --- a/version.py +++ b/version.py @@ -1 +1 @@ -__version__ = "2.0.2" +__version__ = "2.2.0" From 0f2a1cdbc49bdd488e499ead7f3959fe20fa8a73 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 22 Feb 2024 22:31:55 +0100 Subject: [PATCH 10/84] test dev build --- .github/workflows/push_dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push_dev.yml b/.github/workflows/push_dev.yml index f7ec8396..a2399ef2 100644 --- a/.github/workflows/push_dev.yml +++ b/.github/workflows/push_dev.yml @@ -1,8 +1,8 @@ -name: docker-compose-actions-workflow +name: create_dev_images on: push: branches: - - dev + - new env: REGISTRY: ghcr.io From a07f1e543eb04ba09aa47e45512ce21962bf07a1 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 22 Feb 2024 22:47:23 +0100 Subject: [PATCH 11/84] test dev build --- .github/workflows/{push_dev.yml => push-dev.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{push_dev.yml => push-dev.yml} (93%) diff --git a/.github/workflows/push_dev.yml b/.github/workflows/push-dev.yml similarity index 93% rename from .github/workflows/push_dev.yml rename to .github/workflows/push-dev.yml index a2399ef2..22b1561e 100644 --- a/.github/workflows/push_dev.yml +++ b/.github/workflows/push-dev.yml @@ -44,5 +44,5 @@ jobs: context: . file: ${{ matrix.dockerfile }} push: ${{ github.event_name != 'pull_request' }} - tags: "dev" - labels: "dev" + tags: ${{ matrix.image }}:dev + labels: ${{ matrix.image }}:dev From 88ff13f54dd87110b365f0568b479235bfd702dc Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 22 Feb 2024 22:52:45 +0100 Subject: [PATCH 12/84] test dev build --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2740b0e..e1abf943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,6 @@ * evaluate possibility to switch from daphne to uvicorn for asgi [[#982](https://github.com/LDO-CERT/orochi/issues/982)] * Improve path flexibility for local import [[#451](https://github.com/LDO-CERT/orochi/issues/451)] * uv for installing requirements [[#1030](https://github.com/LDO-CERT/orochi/issues/1030)] - *
From 87a82516c980594dee9b74aa9decaafde9a71459 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 22 Feb 2024 23:17:43 +0100 Subject: [PATCH 13/84] test dev build --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 0c06296c..4a931347 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,7 @@ services: build: context: . dockerfile: ./compose/local/nginx/Dockerfile + image: ghcr.io/ldo-cert/orochi_nginx:latest container_name: orochi_nginx depends_on: - django_asgi From a3e51d47cfecd52a43f1d25489c997dc027a2b8e Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 22 Feb 2024 23:29:13 +0100 Subject: [PATCH 14/84] multiple version --- .env.sample | 1 + docker-compose.yml | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 .env.sample diff --git a/.env.sample b/.env.sample new file mode 100644 index 00000000..0fd25230 --- /dev/null +++ b/.env.sample @@ -0,0 +1 @@ +VERSION=latest diff --git a/docker-compose.yml b/docker-compose.yml index 4a931347..8bd1ceb7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: build: context: . dockerfile: ./compose/local/nginx/Dockerfile - image: ghcr.io/ldo-cert/orochi_nginx:latest + image: ghcr.io/ldo-cert/orochi_nginx:${VERSION:-latest} container_name: orochi_nginx depends_on: - django_asgi @@ -36,7 +36,7 @@ services: - http_proxy - https_proxy - local_upload_path - image: ghcr.io/ldo-cert/orochi_django:latest + image: ghcr.io/ldo-cert/orochi_django:${VERSION:-latest} container_name: orochi_django_wsgi hostname: django restart: always @@ -67,7 +67,7 @@ services: - http_proxy - https_proxy - local_upload_path - image: ghcr.io/ldo-cert/orochi_django:latest + image: ghcr.io/ldo-cert/orochi_django:${VERSION:-latest} container_name: orochi_django_asgi hostname: django restart: always @@ -156,7 +156,7 @@ services: MONITORING_ENABLED: "false" scheduler: - image: ghcr.io/ldo-cert/orochi_worker:latest + image: ghcr.io/ldo-cert/orochi_worker:${VERSION:-latest} build: context: . dockerfile: ./compose/local/dask/Dockerfile @@ -188,7 +188,7 @@ services: - cache_path:/root/.cache/volatility3 worker: - image: ghcr.io/ldo-cert/orochi_worker:latest + image: ghcr.io/ldo-cert/orochi_worker:${VERSION:-latest} deploy: replicas: 2 build: From e7cf9f727409b05f69fa6f0aa64abe91674a8932 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 22 Feb 2024 23:31:09 +0100 Subject: [PATCH 15/84] test dev build --- .github/workflows/push-dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push-dev.yml b/.github/workflows/push-dev.yml index 22b1561e..2c63aaeb 100644 --- a/.github/workflows/push-dev.yml +++ b/.github/workflows/push-dev.yml @@ -44,5 +44,5 @@ jobs: context: . file: ${{ matrix.dockerfile }} push: ${{ github.event_name != 'pull_request' }} - tags: ${{ matrix.image }}:dev - labels: ${{ matrix.image }}:dev + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From 7e6009b52a65093f7bb73d3e7a4c2bc959f7e304 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Mon, 26 Feb 2024 14:29:39 +0100 Subject: [PATCH 16/84] python3.12 - go1.22 - ws updates --- .envs/.local/.django | 2 +- .pre-commit-config.yaml | 2 +- compose/local/dask/Dockerfile | 2 +- compose/local/django/Dockerfile | 8 +- compose/local/nginx/conf/default.conf | 4 +- config/routing.py | 10 +- config/settings/base.py | 2 +- orochi/templates/website/index.html | 3 +- orochi/utils/volatility_dask_elk.py | 64 +------- orochi/website/admin.py | 4 +- orochi/website/api/views.py | 10 +- orochi/website/consumers.py | 15 +- orochi/website/defaults.py | 165 ++++++++++++++++++++ orochi/website/middleware.py | 9 +- orochi/website/models.py | 217 ++++++++------------------ orochi/website/routing.py | 4 +- orochi/website/views.py | 16 +- requirements/base.txt | 24 ++- requirements/local.txt | 8 +- 19 files changed, 294 insertions(+), 275 deletions(-) create mode 100644 orochi/website/defaults.py diff --git a/.envs/.local/.django b/.envs/.local/.django index 8180f45e..b1b81839 100755 --- a/.envs/.local/.django +++ b/.envs/.local/.django @@ -52,4 +52,4 @@ no_proxy= # CSRF_TRUSTED_ORIGINS # ------------------------------------------------------------------------------ -CSRF_TRUSTED_ORIGINS=https://orochi.dev +CSRF_TRUSTED_ORIGINS=https://orochi.dev,https://localhost diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bd7c07f7..fce097c6 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-yaml - repo: https://github.com/psf/black - rev: 24.1.1 + rev: 24.2.0 hooks: - id: black diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 7ba87300..3eb103c2 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.1.1-py3.11 +FROM daskdev/dask:dev-py3.12 ENV DEBIAN_FRONTEND noninteractive RUN echo "export VIRTUAL_ENV=`python -c 'import sys; print(sys.prefix)'`" >> /envfile diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index b46c5290..4830290d 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim-buster as common-base +FROM python:3.12-slim-bookworm as common-base ENV DJANGO_SETTINGS_MODULE config.settings.local ENV PYTHONUNBUFFERED 1 @@ -57,10 +57,8 @@ RUN python setup.py build FROM base-builder as go-builder WORKDIR / -RUN curl https://dl.google.com/go/go1.15.2.linux-amd64.tar.gz --output go1.15.2.linux-amd64.tar.gz \ - && tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz -RUN curl https://dl.google.com/go/go1.15.2.linux-amd64.tar.gz --output go1.15.2.linux-amd64.tar.gz \ - && tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz +RUN curl https://dl.google.com/go/go1.22.0.linux-amd64.tar.gz --output go1.22.0.linux-amd64.tar.gz \ + && tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz RUN git clone https://github.com/volatilityfoundation/dwarf2json.git WORKDIR /dwarf2json RUN /usr/local/go/bin/go build diff --git a/compose/local/nginx/conf/default.conf b/compose/local/nginx/conf/default.conf index 336dbdb7..9000964a 100644 --- a/compose/local/nginx/conf/default.conf +++ b/compose/local/nginx/conf/default.conf @@ -23,8 +23,8 @@ server { } server { - listen 443 ssl http2; - listen [::]:443 ssl http2; + listen 443 ssl; + listen [::]:443 ssl; server_name orochi.dev; diff --git a/config/routing.py b/config/routing.py index e662ff08..ccb6943d 100644 --- a/config/routing.py +++ b/config/routing.py @@ -1,13 +1,15 @@ -import orochi.website.routing -from django.core.asgi import get_asgi_application from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter +from channels.security.websocket import AllowedHostsOriginValidator +from django.core.asgi import get_asgi_application + +import orochi.website.routing application = ProtocolTypeRouter( { "http": get_asgi_application(), - "websocket": AuthMiddlewareStack( - URLRouter(orochi.website.routing.websocket_urlpatterns) + "websocket": AllowedHostsOriginValidator( + AuthMiddlewareStack(URLRouter(orochi.website.routing.websocket_urlpatterns)) ), } ) diff --git a/config/settings/base.py b/config/settings/base.py index a47917a0..bfb5a479 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -276,7 +276,7 @@ ASGI_APPLICATION = "config.routing.application" CHANNEL_LAYERS = { "default": { - "BACKEND": "channels_redis.pubsub.RedisPubSubChannelLayer", + "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [(env("REDIS_SERVER"), env("REDIS_PORT"))], }, diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index e75d5f7a..11b95a2a 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -148,7 +148,8 @@
History Log
}); // WS, UPDATE NOTE - const chatSocket = new WebSocket(`ws://${window.location.host}/ws/notify/{{ user.pk }}/`); + var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; + const chatSocket = new WebSocket(`${ws_scheme}://${window.location.host}/ws/notify/{{ user.pk }}/`); chatSocket.onmessage = function (e) { const data = JSON.parse(e.data); const text = data.message.split("||")[1]; diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index 6a6ae2ba..c1c7e4ad 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -21,15 +21,13 @@ import requests import volatility3.plugins import vt -from asgiref.sync import async_to_sync, sync_to_async +from asgiref.sync import sync_to_async from bs4 import BeautifulSoup -from channels.layers import DEFAULT_CHANNEL_LAYER, channel_layers from clamdpy import ClamdUnixSocket from distributed import fire_and_forget, get_client, rejoin, secede from django.conf import settings from elasticsearch import Elasticsearch, helpers from elasticsearch_dsl import Search -from guardian.shortcuts import get_users_with_perms from regipy.registry import RegistryHive from volatility3 import cli, framework from volatility3.cli.text_renderer import ( @@ -56,7 +54,7 @@ ListRequirement, ) -from orochi.website.models import ( +from orochi.website.defaults import ( DUMP_STATUS_COMPLETED, DUMP_STATUS_ERROR, DUMP_STATUS_MISSING_SYMBOLS, @@ -68,11 +66,8 @@ RESULT_STATUS_SUCCESS, RESULT_STATUS_UNSATISFIED, SERVICE_VIRUSTOTAL, - CustomRule, - Dump, - Result, - Service, ) +from orochi.website.models import CustomRule, Dump, Result, Service BANNER_REGEX = r'^"?Linux version (?P\S+) (?P.+) \(((?Pgcc.+)) #(?P\d+)(?P.+)$"?' @@ -83,16 +78,6 @@ "Changed Date": "#FFFF00", } -TOAST_COLORS = { - 0: "blue", - 1: "yellow", - 2: "green", - 3: "green", - 4: "orange", - 5: "red", - 6: "black", -} - class MuteProgress(object): """ @@ -326,41 +311,6 @@ def run_regipy(filepath): logging.error(e) -def send_to_ws(dump, result=None, plugin_name=None, message=None, color=None): - """ - Notifies plugin result to websocket - """ - - users = get_users_with_perms(dump, only_with_perms_in=["can_see"]) - channel_layer = channel_layers.make_backend(DEFAULT_CHANNEL_LAYER) - if not channel_layer: - return - for user in users: - if result and plugin_name: - async_to_sync(channel_layer.group_send)( - f"chat_{user.pk}", - { - "type": "chat_message", - "message": f"""{datetime.datetime.now().strftime("%d/%m/%Y %H:%M")}||""" - f"""Plugin {plugin_name} on dump {dump.name} ended
""" - f"""Status: {result.get_result_display()}""", - }, - ) - elif message and color: - async_to_sync(channel_layer.group_send)( - f"chat_{user.pk}", - { - "type": "chat_message", - "message": f"""{datetime.datetime.now().strftime("%d/%m/%Y %H:%M")}||""" - f"""Message on dump {dump.name}
{message}""", - }, - ) - try: - channel_layer.close() - except RuntimeError as excp: - logging.error(str(excp)) - - def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None): """ Execute a single plugin on a dump with optional params. @@ -599,7 +549,6 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None): result.save() logging.debug(f"[dump {dump_obj.pk} - plugin {plugin_obj.pk}] empty") - send_to_ws(dump_obj, result, plugin_obj.name) return 0 except Exception as excp: @@ -609,7 +558,6 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None): result.result = RESULT_STATUS_ERROR result.description = "\n".join(fulltrace) result.save() - send_to_ws(dump_obj, result, plugin_obj.name) logging.error(f"[dump {dump_obj.pk} - plugin {plugin_obj.pk}] generic error") return 0 @@ -910,9 +858,6 @@ def unzip_then_run(dump_pk, user_pk, password, restart, move): for result in tasks_list: result.result = RESULT_STATUS_DISABLED result.save() - send_to_ws( - dump, message="Missing symbols! All plugin are disabled", color=4 - ) except Exception as excp: logging.error(f"[dump {dump_pk}] - {excp}") dump.description = excp @@ -926,6 +871,3 @@ def unzip_then_run(dump_pk, user_pk, password, restart, move): for result in tasks_list: result.result = RESULT_STATUS_DISABLED result.save() - send_to_ws( - dump, message="Error in file creation! All plugin are disabled", color=4 - ) diff --git a/orochi/website/admin.py b/orochi/website/admin.py index 9e876000..97af26bd 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -1,19 +1,17 @@ from allauth.socialaccount.models import SocialAccount, SocialApp, SocialToken from django.contrib import admin from django.contrib.auth.models import Group -from django.db import models from django_admin_listfilter_dropdown.filters import RelatedDropdownFilter from django_admin_multiple_choice_list_filter.list_filters import ( MultipleChoiceListFilter, ) from django_file_form.model_admin import FileFormAdmin from django_file_form.models import TemporaryUploadedFile -from django_json_widget.widgets import JSONEditorWidget from guardian.admin import GuardedModelAdmin +from orochi.website.defaults import RESULT from orochi.website.forms import PluginCreateAdminForm, PluginEditAdminForm from orochi.website.models import ( - RESULT, Bookmark, CustomRule, Dump, diff --git a/orochi/website/api/views.py b/orochi/website/api/views.py index 4f25fdec..57bdb212 100644 --- a/orochi/website/api/views.py +++ b/orochi/website/api/views.py @@ -36,14 +36,8 @@ ShortDumpSerializer, ShortResultSerializer, ) -from orochi.website.models import ( - RESULT_STATUS_NOT_STARTED, - RESULT_STATUS_RUNNING, - Dump, - Plugin, - Result, - UserPlugin, -) +from orochi.website.defaults import RESULT_STATUS_NOT_STARTED, RESULT_STATUS_RUNNING +from orochi.website.models import Dump, Plugin, Result, UserPlugin from orochi.website.views import index_f_and_f, plugin_f_and_f diff --git a/orochi/website/consumers.py b/orochi/website/consumers.py index 5fa42a49..48d3c67e 100644 --- a/orochi/website/consumers.py +++ b/orochi/website/consumers.py @@ -1,4 +1,5 @@ import json +import logging from channels.generic.websocket import AsyncWebsocketConsumer @@ -7,25 +8,27 @@ class NotifyConsumer(AsyncWebsocketConsumer): async def connect(self): # User connects to his update channel self.room_name = self.scope["url_route"]["kwargs"]["user_id"] - self.room_group_name = f"chat_{self.room_name}" - await self.channel_layer.group_add(self.room_group_name, self.channel_name) + await self.channel_layer.group_add(f"chat_{self.room_name}", self.channel_name) + logging.info(f"User connected to chat_{self.room_name} - {self.channel_name}") await self.accept() async def disconnect(self, close_code): # User leaves room group + logging.info( + f"User disconnected from {self.room_group_name} - {self.channel_name}" + ) await self.channel_layer.group_discard(self.room_group_name, self.channel_name) async def receive(self, text_data): # Receive message from WebSocket text_data_json = json.loads(text_data) - message = text_data_json["message"] # Send message to room group await self.channel_layer.group_send( - self.room_group_name, {"type": "chat_message", "message": message} + self.room_group_name, + {"type": "chat_message", "message": text_data_json["message"]}, ) async def chat_message(self, event): # Receive message from room group - message = event["message"] - await self.send(text_data=json.dumps({"message": message})) + await self.send(text_data=json.dumps({"message": event["message"]})) diff --git a/orochi/website/defaults.py b/orochi/website/defaults.py new file mode 100644 index 00000000..2c5dc032 --- /dev/null +++ b/orochi/website/defaults.py @@ -0,0 +1,165 @@ +OPERATING_SYSTEM = ( + ("Linux", "Linux"), + ("Windows", "Windows"), + ("Mac", "Mac"), + ("Other", "Other"), +) + +TOAST_RESULT_COLORS = { + 0: "blue", + 1: "yellow", + 2: "green", + 3: "green", + 4: "orange", + 5: "red", + 6: "black", +} + +TOAST_DUMP_COLORS = { + 1: "green", + 2: "green", + 3: "red", + 4: "red", + 5: "orange", +} + +SERVICE_VIRUSTOTAL = 1 +SERVICE_MISP = 2 +SERVICE_MAXMIND = 3 +SERVICES = ( + (SERVICE_VIRUSTOTAL, "VirusTotal"), + (SERVICE_MISP, "MISP"), + (SERVICE_MAXMIND, "MAXMIND"), +) + +DUMP_STATUS_CREATED = 1 +DUMP_STATUS_COMPLETED = 2 +DUMP_STATUS_DELETED = 3 +DUMP_STATUS_ERROR = 4 +DUMP_STATUS_MISSING_SYMBOLS = 5 +STATUS = ( + (DUMP_STATUS_CREATED, "Created"), + (DUMP_STATUS_COMPLETED, "Completed"), + (DUMP_STATUS_DELETED, "Deleted"), + (DUMP_STATUS_ERROR, "Error"), + (DUMP_STATUS_MISSING_SYMBOLS, "Missing Symbols"), +) + +RESULT_STATUS_NOT_STARTED = 0 +RESULT_STATUS_RUNNING = 1 +RESULT_STATUS_EMPTY = 2 +RESULT_STATUS_SUCCESS = 3 +RESULT_STATUS_UNSATISFIED = 4 +RESULT_STATUS_ERROR = 5 +RESULT_STATUS_DISABLED = 6 +RESULT = ( + (RESULT_STATUS_NOT_STARTED, "Not Started"), + (RESULT_STATUS_RUNNING, "Running"), + (RESULT_STATUS_EMPTY, "Empty"), + (RESULT_STATUS_SUCCESS, "Success"), + (RESULT_STATUS_UNSATISFIED, "Unsatisfied"), + (RESULT_STATUS_ERROR, "Error"), + (RESULT_STATUS_DISABLED, "Disabled"), +) +ICONS = ( + ("ss-arn", "Arabian Nights"), + ("ss-atq", "Antiquities"), + ("ss-leg", "Legends"), + ("ss-drk", "The Dark"), + ("ss-fem", "Fallen Empires"), + ("ss-hml", "Homelands"), + ("ss-ice", "Ice Age"), + ("ss-ice2", "Ice Age (Original)"), + ("ss-all", "Alliances"), + ("ss-csp", "Coldsnap"), + ("ss-mir", "Mirage"), + ("ss-vis", "Visions"), + ("ss-wth", "Weatherlight"), + ("ss-tmp", "Tempest"), + ("ss-sth", "Stronghold"), + ("ss-exo", "Exodus"), + ("ss-usg", "Urza's Saga"), + ("ss-ulg", "Urza's Legacy"), + ("ss-uds", "Urza's Destiny"), + ("ss-mmq", "Mercadian Masques"), + ("ss-nem", "Nemesis"), + ("ss-pcy", "Prophecy"), + ("ss-inv", "Invasion"), + ("ss-pls", "Planeshift"), + ("ss-apc", "Apocalypse"), + ("ss-ody", "Odyssey"), + ("ss-tor", "Torment"), + ("ss-jud", "Judgement"), + ("ss-ons", "Onslaught"), + ("ss-lgn", "Legions"), + ("ss-scg", "Scourge"), + ("ss-mrd", "Mirrodin"), + ("ss-dst", "Darksteel"), + ("ss-5dn", "Fifth Dawn"), + ("ss-chk", "Champions of Kamigawa"), + ("ss-bok", "Betrayers of Kamigawa"), + ("ss-sok", "Saviors of Kamigawa"), + ("ss-rav", "Ravnica"), + ("ss-gpt", "Guildpact"), + ("ss-dis", "Dissension"), + ("ss-tsp", "Time Spiral"), + ("ss-plc", "Planar Chaos"), + ("ss-fut", "Future Sight"), + ("ss-lrw", "Lorwyn"), + ("ss-mor", "Morningtide"), + ("ss-shm", "Shadowmoor"), + ("ss-eve", "Eventide"), + ("ss-ala", "Shards of Alara"), + ("ss-con", "Conflux"), + ("ss-arb", "Alara Reborn"), + ("ss-zen", "Zendikar"), + ("ss-wwk", "Worldwake"), + ("ss-roe", "Rise of the Eldrazi"), + ("ss-som", "Scars of Mirrodin"), + ("ss-mbs", "Mirrodin Besieged"), + ("ss-nph", "New Phyrexia"), + ("ss-isd", "Innistrad"), + ("ss-dka", "Dark Ascension"), + ("ss-avr", "Avacyn Restored"), + ("ss-rtr", "Return to Ravnica"), + ("ss-gtc", "Gatecrash"), + ("ss-dgm", "Dragon's Maze"), + ("ss-ths", "Theros"), + ("ss-bng", "Born of the Gods"), + ("ss-jou", "Journey into Nyx"), + ("ss-ktk", "Khans of Tarkir"), + ("ss-frf", "Fate Reforged"), + ("ss-dtk", "Dragons of Tarkir"), + ("ss-bfz", "Battle for Zendikar"), + ("ss-ogw", "Oath of the Gatewatch"), + ("ss-soi", "Shadows Over Innistrad"), + ("ss-emn", "Eldritch Moon"), + ("ss-kld", "Kaladesh"), + ("ss-aer", "Aether Revolt"), + ("ss-akh", "Amonkhet"), + ("ss-hou", "Hour of Devastation"), + ("ss-xln", "Ixalan"), + ("ss-rix", "Rivals of Ixalan"), + ("ss-dom", "Dominaria"), + ("ss-grn", "Guilds of Ravnica"), + ("ss-rna", "Ravnica Allegiance"), + ("ss-war", "War of the Spark"), + ("ss-eld", "Throne of Eldraine"), + ("ss-thb", "Theros: Beyond Death"), + ("ss-iko", "koria: Lair of Behemoths"), + ("ss-znr", "Zendikar Rising"), + ("ss-khm", "Kaldheim"), + ("ss-stx", "Strixhaven: School of Mages"), + ("ss-mid", "Innistrad: Midnight Hunt"), + ("ss-vow", "Innistrad: Crimson Vow"), + ("ss-neo", "Kamigawa: Neon Dynasty"), + ("ss-snc", "Streets of New Capenna"), + ("ss-dmu", "Dominaria United"), + ("ss-bro", "The Brothers' War"), + ("ss-one", "Phyrexia: All Will Be One"), + ("ss-mom", "March of the Machine"), + ("ss-mat", "March of the Machine: The Aftermath"), + ("ss-woe", "Wilds of Eldraine"), +) + +DEFAULT_YARA_PATH = "/yara/default.yara" diff --git a/orochi/website/middleware.py b/orochi/website/middleware.py index 712f20ff..168fef2e 100644 --- a/orochi/website/middleware.py +++ b/orochi/website/middleware.py @@ -3,12 +3,13 @@ from django.urls import reverse from guardian.shortcuts import get_objects_for_user -from orochi.website.models import ( +from orochi.website.defaults import ( RESULT_STATUS_DISABLED, RESULT_STATUS_NOT_STARTED, RESULT_STATUS_RUNNING, - Bookmark, + TOAST_RESULT_COLORS, ) +from orochi.website.models import Bookmark class UpdatesMiddleware: @@ -28,15 +29,13 @@ def process_template_response(self, request, response): ): news = [] - colors = {2: "green", 3: "green", 4: "yellow", 5: "red"} - dumps = get_objects_for_user(request.user, "website.can_see") for dump in dumps: news.extend( { "date": result.updated_at, "text": f"Plugin {result.plugin.name} on dump {dump.name} ended
" - f"Status: {result.get_result_display()}", + f"Status: {result.get_result_display()}", } for result in dump.result_set.exclude( result__in=[ diff --git a/orochi/website/models.py b/orochi/website/models.py index cd140ca5..5fae3808 100644 --- a/orochi/website/models.py +++ b/orochi/website/models.py @@ -1,5 +1,8 @@ import os +from datetime import datetime +from asgiref.sync import async_to_sync +from channels.layers import get_channel_layer from colorfield.fields import ColorField from django.conf import settings from django.contrib.auth import get_user_model @@ -7,157 +10,20 @@ from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver -from guardian.shortcuts import assign_perm - -from orochi.ya.models import Ruleset - -OPERATING_SYSTEM = ( - ("Linux", "Linux"), - ("Windows", "Windows"), - ("Mac", "Mac"), - ("Other", "Other"), -) - -SERVICE_VIRUSTOTAL = 1 -SERVICE_MISP = 2 -SERVICE_MAXMIND = 3 -SERVICES = ( - (SERVICE_VIRUSTOTAL, "VirusTotal"), - (SERVICE_MISP, "MISP"), - (SERVICE_MAXMIND, "MAXMIND"), -) - -DUMP_STATUS_CREATED = 1 -DUMP_STATUS_COMPLETED = 2 -DUMP_STATUS_DELETED = 3 -DUMP_STATUS_ERROR = 4 -DUMP_STATUS_MISSING_SYMBOLS = 5 -STATUS = ( - (DUMP_STATUS_CREATED, "Created"), - (DUMP_STATUS_COMPLETED, "Completed"), - (DUMP_STATUS_DELETED, "Deleted"), - (DUMP_STATUS_ERROR, "Error"), - (DUMP_STATUS_MISSING_SYMBOLS, "Missing Symbols"), -) - -RESULT_STATUS_NOT_STARTED = 0 -RESULT_STATUS_RUNNING = 1 -RESULT_STATUS_EMPTY = 2 -RESULT_STATUS_SUCCESS = 3 -RESULT_STATUS_UNSATISFIED = 4 -RESULT_STATUS_ERROR = 5 -RESULT_STATUS_DISABLED = 6 -RESULT = ( - (RESULT_STATUS_NOT_STARTED, "Not Started"), - (RESULT_STATUS_RUNNING, "Running"), - (RESULT_STATUS_EMPTY, "Empty"), - (RESULT_STATUS_SUCCESS, "Success"), - (RESULT_STATUS_UNSATISFIED, "Unsatisfied"), - (RESULT_STATUS_ERROR, "Error"), - (RESULT_STATUS_DISABLED, "Disabled"), +from guardian.shortcuts import assign_perm, get_users_with_perms + +from orochi.website.defaults import ( + DEFAULT_YARA_PATH, + ICONS, + OPERATING_SYSTEM, + RESULT, + RESULT_STATUS_NOT_STARTED, + SERVICES, + STATUS, + TOAST_DUMP_COLORS, + TOAST_RESULT_COLORS, ) -ICONS = ( - ("ss-arn", "Arabian Nights"), - ("ss-atq", "Antiquities"), - ("ss-leg", "Legends"), - ("ss-drk", "The Dark"), - ("ss-fem", "Fallen Empires"), - ("ss-hml", "Homelands"), - ("ss-ice", "Ice Age"), - ("ss-ice2", "Ice Age (Original)"), - ("ss-all", "Alliances"), - ("ss-csp", "Coldsnap"), - ("ss-mir", "Mirage"), - ("ss-vis", "Visions"), - ("ss-wth", "Weatherlight"), - ("ss-tmp", "Tempest"), - ("ss-sth", "Stronghold"), - ("ss-exo", "Exodus"), - ("ss-usg", "Urza's Saga"), - ("ss-ulg", "Urza's Legacy"), - ("ss-uds", "Urza's Destiny"), - ("ss-mmq", "Mercadian Masques"), - ("ss-nem", "Nemesis"), - ("ss-pcy", "Prophecy"), - ("ss-inv", "Invasion"), - ("ss-pls", "Planeshift"), - ("ss-apc", "Apocalypse"), - ("ss-ody", "Odyssey"), - ("ss-tor", "Torment"), - ("ss-jud", "Judgement"), - ("ss-ons", "Onslaught"), - ("ss-lgn", "Legions"), - ("ss-scg", "Scourge"), - ("ss-mrd", "Mirrodin"), - ("ss-dst", "Darksteel"), - ("ss-5dn", "Fifth Dawn"), - ("ss-chk", "Champions of Kamigawa"), - ("ss-bok", "Betrayers of Kamigawa"), - ("ss-sok", "Saviors of Kamigawa"), - ("ss-rav", "Ravnica"), - ("ss-gpt", "Guildpact"), - ("ss-dis", "Dissension"), - ("ss-tsp", "Time Spiral"), - ("ss-plc", "Planar Chaos"), - ("ss-fut", "Future Sight"), - ("ss-lrw", "Lorwyn"), - ("ss-mor", "Morningtide"), - ("ss-shm", "Shadowmoor"), - ("ss-eve", "Eventide"), - ("ss-ala", "Shards of Alara"), - ("ss-con", "Conflux"), - ("ss-arb", "Alara Reborn"), - ("ss-zen", "Zendikar"), - ("ss-wwk", "Worldwake"), - ("ss-roe", "Rise of the Eldrazi"), - ("ss-som", "Scars of Mirrodin"), - ("ss-mbs", "Mirrodin Besieged"), - ("ss-nph", "New Phyrexia"), - ("ss-isd", "Innistrad"), - ("ss-dka", "Dark Ascension"), - ("ss-avr", "Avacyn Restored"), - ("ss-rtr", "Return to Ravnica"), - ("ss-gtc", "Gatecrash"), - ("ss-dgm", "Dragon's Maze"), - ("ss-ths", "Theros"), - ("ss-bng", "Born of the Gods"), - ("ss-jou", "Journey into Nyx"), - ("ss-ktk", "Khans of Tarkir"), - ("ss-frf", "Fate Reforged"), - ("ss-dtk", "Dragons of Tarkir"), - ("ss-bfz", "Battle for Zendikar"), - ("ss-ogw", "Oath of the Gatewatch"), - ("ss-soi", "Shadows Over Innistrad"), - ("ss-emn", "Eldritch Moon"), - ("ss-kld", "Kaladesh"), - ("ss-aer", "Aether Revolt"), - ("ss-akh", "Amonkhet"), - ("ss-hou", "Hour of Devastation"), - ("ss-xln", "Ixalan"), - ("ss-rix", "Rivals of Ixalan"), - ("ss-dom", "Dominaria"), - ("ss-grn", "Guilds of Ravnica"), - ("ss-rna", "Ravnica Allegiance"), - ("ss-war", "War of the Spark"), - ("ss-eld", "Throne of Eldraine"), - ("ss-thb", "Theros: Beyond Death"), - ("ss-iko", "koria: Lair of Behemoths"), - ("ss-znr", "Zendikar Rising"), - ("ss-khm", "Kaldheim"), - ("ss-stx", "Strixhaven: School of Mages"), - ("ss-mid", "Innistrad: Midnight Hunt"), - ("ss-vow", "Innistrad: Crimson Vow"), - ("ss-neo", "Kamigawa: Neon Dynasty"), - ("ss-snc", "Streets of New Capenna"), - ("ss-dmu", "Dominaria United"), - ("ss-bro", "The Brothers' War"), - ("ss-one", "Phyrexia: All Will Be One"), - ("ss-mom", "March of the Machine"), - ("ss-mat", "March of the Machine: The Aftermath"), - ("ss-woe", "Wilds of Eldraine"), -) - -DEFAULT_YARA_PATH = "/yara/default.yara" +from orochi.ya.models import Ruleset class Service(models.Model): @@ -354,3 +220,54 @@ def new_plugin(sender, instance, created, **kwargs): # Add new plugin to user for user in get_user_model().objects.all(): up, created = UserPlugin.objects.get_or_create(user=user, plugin=instance) + + +@staticmethod +@receiver(post_save, sender=Dump) +def dump_saved(sender, instance, created, **kwargs): + users = get_users_with_perms(instance, only_with_perms_in=["can_see"]) + if created: + message = f"Dump {instance.name} has been created" + else: + message = f"Dump {instance.name} has been updated." + + message = f"{datetime.now()} || {message}
Status: {instance.get_status_display()}" + + for user in users: + # Send message to room group + channel_layer = get_channel_layer() + async_to_sync(channel_layer.group_send)( + f"chat_{user.pk}", + { + "type": "chat_message", + "message": message, + }, + ) + + +@staticmethod +@receiver(post_save, sender=Result) +def result_saved(sender, instance, created, **kwargs): + dump = instance.dump + users = get_users_with_perms(dump, only_with_perms_in=["can_see"]) + if created: + message = ( + f"Plugin {instance.plugin.name} on {instance.dump.name} has been created" + ) + else: + message = ( + f"Plugin {instance.plugin.name} on {instance.dump.name} has been updated" + ) + + message = f"{datetime.now()} || {message}
Status: {instance.get_result_display()}" + + for user in users: + # Send message to room group + channel_layer = get_channel_layer() + async_to_sync(channel_layer.group_send)( + f"chat_{user.pk}", + { + "type": "chat_message", + "message": message, + }, + ) diff --git a/orochi/website/routing.py b/orochi/website/routing.py index 1ff257e3..63ca8754 100644 --- a/orochi/website/routing.py +++ b/orochi/website/routing.py @@ -1,7 +1,7 @@ from django.urls import re_path -from . import consumers +from orochi.website.consumers import NotifyConsumer websocket_urlpatterns = [ - re_path(r"ws/notify/(?P\w+)/$", consumers.NotifyConsumer.as_asgi()), + re_path(r"ws/notify/(?P\w+)/$", NotifyConsumer.as_asgi()), ] diff --git a/orochi/website/views.py b/orochi/website/views.py index e480cc2b..e0682ca6 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -49,6 +49,15 @@ run_plugin, unzip_then_run, ) +from orochi.website.defaults import ( + DUMP_STATUS_COMPLETED, + RESULT_STATUS_DISABLED, + RESULT_STATUS_EMPTY, + RESULT_STATUS_NOT_STARTED, + RESULT_STATUS_RUNNING, + RESULT_STATUS_SUCCESS, + SERVICE_MISP, +) from orochi.website.forms import ( BookmarkForm, DumpForm, @@ -62,13 +71,6 @@ SymbolUploadForm, ) from orochi.website.models import ( - DUMP_STATUS_COMPLETED, - RESULT_STATUS_DISABLED, - RESULT_STATUS_EMPTY, - RESULT_STATUS_NOT_STARTED, - RESULT_STATUS_RUNNING, - RESULT_STATUS_SUCCESS, - SERVICE_MISP, Bookmark, CustomRule, Dump, diff --git a/requirements/base.txt b/requirements/base.txt index daa0435a..b8a1f45b 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -28,7 +28,7 @@ channels_redis==4.2.0 # https://github.com/joke2k/django-environ django-environ==0.11.2 # https://github.com/pennersr/django-allauth -django-allauth==0.60.1 +django-allauth==0.61.1 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==2.1 # https://github.com/jazzband/django-redis @@ -51,7 +51,7 @@ drf-yasg==1.21.7 # Django tweak # ------------------------------------------------------------------------------ # https://github.com/django-crispy-forms/crispy-bootstrap5 -crispy-bootstrap5==2023.10 +crispy-bootstrap5==2024.2 # https://github.com/fabiocaccamo/django-colorfield django-colorfield==0.11.0 # https://github.com/mbraak/django-file-form @@ -70,7 +70,7 @@ django-admin-multiple-choice-list-filter==0.1.1 # Elasticsearch # ------------------------------------------------------------------------------ # https://github.com/elastic/elasticsearch-py -elasticsearch==8.12.0 +elasticsearch==8.12.1 # https://github.com/elastic/elasticsearch-dsl-py elasticsearch-dsl==8.12.0 # https://github.com/jurismarches/luqum @@ -79,13 +79,11 @@ luqum==0.13.0 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.1.1 +dask==2024.2.1 # https://github.com/dask/distributed -distributed==2024.1.1 +distributed==2024.2.1 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.0.7 -# https://github.com/blosc/python-blosc -blosc==1.11.1 # https://github.com/python-lz4/python-lz4 lz4==4.3.3 # https://numpy.org/ @@ -93,7 +91,7 @@ numpy==1.26.4 # https://github.com/cloudpipe/cloudpickle cloudpickle==3.0.0 # https://pypi.org/project/toolz/ -toolz==0.12.0 +toolz==0.12.1 # https://pypi.org/project/tornado/ tornado==6.4 @@ -101,7 +99,7 @@ tornado==6.4 # ------------------------------------------------------------------------------ # https://github.com/volatilityfoundation/ # volatility3==2.5.0 -volatility3 @ git+https://github.com/volatilityfoundation/volatility3.git@6d34e43667a4f709902f3c157a4e54ec4ed679ce#egg=volatility3 +volatility3 @ git+https://github.com/volatilityfoundation/volatility3.git@887747e3ceb1d40af936e8a91d65e05874f4c06a#egg=volatility3 # https://github.com/VirusTotal/yara-python #yara-python==4.1.0 # https://github.com/Viicos/clamdpy @@ -109,7 +107,7 @@ clamdpy==0.1.0.post1 # https://github.com/VirusTotal/vt-py vt-py==0.18.0 # https://github.com/mkorman90/regipy/ -regipy==3.1.6 +regipy==4.0.0 # http://www.capstone-engine.org/ capstone==5.0.1 # https://github.com/Julian/jsonschema @@ -122,9 +120,9 @@ geoip2==4.8.0 # Yara # ------------------------------------------------------------------------------ # https://github.com/gitpython-developers/GitPython -GitPython==3.1.41 +GitPython==3.1.42 # https://github.com/frostming/marko -marko==2.0.2 +marko==2.0.3 # symbols dwarf # ------------------------------------------------------------------------------ @@ -140,7 +138,7 @@ pefile==2023.2.7 # misp export # ------------------------------------------------------------------------------ # https://github.com/MISP/PyMISP -pymisp==2.4.184.2 +pymisp==2.4.185 # ldap # ------------------------------------------------------------------------------ diff --git a/requirements/local.txt b/requirements/local.txt index 9fc15249..3b873173 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -7,7 +7,7 @@ mypy==1.8.0 # https://github.com/typeddjango/django-stubs django-stubs==4.2.7 # https://github.com/pytest-dev/pytest -pytest==8.0.0 +pytest==8.0.2 # https://github.com/Frozenball/pytest-sugar pytest-sugar==1.0.0 @@ -18,13 +18,13 @@ flake8==7.0.0 # https://github.com/gforcada/flake8-isort flake8-isort==6.1.1 # https://github.com/nedbat/coveragepy -coverage==7.4.1 +coverage==7.4.3 # https://github.com/ambv/black -black==24.1.1 +black==24.2.0 # https://github.com/PyCQA/pylint-django pylint-django==2.5.5 # https://github.com/pre-commit/pre-commit -pre-commit==3.6.0 +pre-commit==3.6.2 # Django # ------------------------------------------------------------------------------ From 7003a2a2ed33559f52ddaa64a6078e5f691e0ab3 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Mon, 26 Feb 2024 14:50:14 +0100 Subject: [PATCH 17/84] python3.12 - go1.22 - ws updates --- orochi/website/consumers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/orochi/website/consumers.py b/orochi/website/consumers.py index 48d3c67e..656282ed 100644 --- a/orochi/website/consumers.py +++ b/orochi/website/consumers.py @@ -8,8 +8,9 @@ class NotifyConsumer(AsyncWebsocketConsumer): async def connect(self): # User connects to his update channel self.room_name = self.scope["url_route"]["kwargs"]["user_id"] - await self.channel_layer.group_add(f"chat_{self.room_name}", self.channel_name) - logging.info(f"User connected to chat_{self.room_name} - {self.channel_name}") + self.room_group_name = f"chat_{self.room_name}" + await self.channel_layer.group_add(self.room_group_name, self.channel_name) + logging.info(f"User connected to {self.room_group_name} - {self.channel_name}") await self.accept() async def disconnect(self, close_code): From 7e4c1f6834a13d0d9bce06d844f3a080ce04883e Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 29 Feb 2024 16:40:41 +0100 Subject: [PATCH 18/84] #1030 update - #947 method 1 --- .envs/.local/.django | 8 +++++ compose/local/dask/Dockerfile | 5 ++- compose/local/django/Dockerfile | 3 +- compose/local/nginx/conf/default.conf | 8 ++--- config/settings/local.py | 2 +- docker-compose.yml | 13 +++---- orochi/templates/base.html | 11 ++++-- orochi/templates/website/index.html | 4 ++- orochi/templates/website/partial_indices.html | 5 +-- orochi/templates/website/partial_note.html | 2 ++ orochi/users/views.py | 33 ++++++++++++++--- orochi/website/api/permissions.py | 25 ++++++++----- .../migrations/0053_create_default_groups.py | 14 ++++++++ orochi/website/templatetags/custom_tags.py | 6 ++++ orochi/website/views.py | 35 ++++++++++++++++++- 15 files changed, 138 insertions(+), 36 deletions(-) create mode 100644 orochi/website/migrations/0053_create_default_groups.py diff --git a/.envs/.local/.django b/.envs/.local/.django index b1b81839..e7dc3102 100755 --- a/.envs/.local/.django +++ b/.envs/.local/.django @@ -7,6 +7,14 @@ IPYTHONDIR=/app/.ipython # ------------------------------------------------------------------------------ ALLOWED_HOSTS=* +# Smtp +# ------------------------------------------------------------------------------ +EMAIL_HOST=mailpit +EMAIL_PORT=1025 +EMAIL_USE_TLS=False +EMAIL_HOST_USER= +EMAIL_HOST_PASSWORD= + # Redis # ------------------------------------------------------------------------------ REDIS_URL=redis://redis:6379/0 diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 3eb103c2..ae445f63 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,6 +1,5 @@ -FROM daskdev/dask:dev-py3.12 +FROM daskdev/dask:2024.2.1-py3.12 ENV DEBIAN_FRONTEND noninteractive -RUN echo "export VIRTUAL_ENV=`python -c 'import sys; print(sys.prefix)'`" >> /envfile ARG local_folder=/uploads @@ -48,7 +47,7 @@ RUN python setup.py build \ # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN . /envfile && pip install uv==0.1.7 && uv pip install --no-cache -r /requirements/base.txt +RUN pip install uv==0.1.12 && uv pip install --system --no-cache -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh RUN chmod +x /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 4830290d..f47e5a21 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -3,7 +3,6 @@ FROM python:3.12-slim-bookworm as common-base ENV DJANGO_SETTINGS_MODULE config.settings.local ENV PYTHONUNBUFFERED 1 ENV PYTHONDONTWRITEBYTECODE 1 -RUN echo "export VIRTUAL_ENV=`python -c 'import sys; print(sys.prefix)'`" >> /envfile ARG local_folder=/uploads @@ -66,7 +65,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN . /envfile && pip install uv==0.1.7 && uv pip install --no-cache -r /requirements/base.txt +RUN pip install uv==0.1.12 && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/compose/local/nginx/conf/default.conf b/compose/local/nginx/conf/default.conf index 9000964a..7a105d90 100644 --- a/compose/local/nginx/conf/default.conf +++ b/compose/local/nginx/conf/default.conf @@ -14,12 +14,8 @@ map $http_upgrade $connection_upgrade { server { listen 80; listen [::]:80; - server_name orochi.dev; - location / { - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header Host $http_host; - proxy_pass http://django_wsgi; - } + server_name _; + return 301 https://$host$request_uri; } server { diff --git a/config/settings/local.py b/config/settings/local.py index ed6bdd56..da468de2 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -27,7 +27,7 @@ # EMAIL # ------------------------------------------------------------------------------ -EMAIL_HOST = env("EMAIL_HOST", default="mailhog") +EMAIL_HOST = env("EMAIL_HOST", default="mailpit") EMAIL_PORT = 1025 EMAIL_USE_TLS = env("EMAIL_USE_TLS", default=True) EMAIL_HOST_USER = env("EMAIL_HOST_USER", default=None) diff --git a/docker-compose.yml b/docker-compose.yml index 8bd1ceb7..25348c65 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,7 +42,7 @@ services: restart: always depends_on: - postgres - - mailhog + - mailpit volumes: - media_path:/media - symbols_path:/src/volatility3/volatility3/symbols @@ -73,7 +73,7 @@ services: restart: always depends_on: - postgres - - mailhog + - mailpit volumes: - media_path:/media - symbols_path:/src/volatility3/volatility3/symbols @@ -103,12 +103,13 @@ services: ports: - "5432:5432" - mailhog: - image: mailhog/mailhog:v1.0.1 - container_name: orochi_mailhog - hostname: mailhog + mailpit: + image: 'axllent/mailpit:latest' + container_name: orochi_mailpit + hostname: mailpit restart: always ports: + - "1025:1025" - "8025:8025" redis: diff --git a/orochi/templates/base.html b/orochi/templates/base.html index d4aa82c5..3762c03f 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -1,4 +1,4 @@ -{% load static i18n %} +{% load static i18n custom_tags %} @@ -36,23 +36,30 @@ {% if request.user.is_authenticated %}
diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index ae445f63..9ee626df 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.2.1-py3.12 +FROM daskdev/dask:2024.3.0-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -47,7 +47,7 @@ RUN python setup.py build \ # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.12 && uv pip install --system --no-cache -r /requirements/base.txt +RUN pip install uv==0.1.21 && uv pip install --system --no-cache -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh RUN chmod +x /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index f47e5a21..88e9e43b 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -65,7 +65,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.12 && uv pip install --no-cache --system -r /requirements/base.txt +RUN pip install uv==0.1.21 && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/orochi/static/README.txt b/orochi/static/README.txt index 82b57963..4b083068 100644 --- a/orochi/static/README.txt +++ b/orochi/static/README.txt @@ -22,10 +22,9 @@ --> http://bootboxjs.com/ --> version 6.0.0 -# jstree [TREE VIEW FOR PSTREE] ---> https://www.jstree.com/ ---> version 3.3.16 ---> with plugin jstree-table https://github.com/adamjimenez/jstree-table +# wunderbaum [TREE VIEW FOR PSTREE] +--> https://github.com/mar10/wunderbaum/ +--> version 0.8.2 # Datatables [TABLE RENDERING] --> https://datatables.net/ diff --git a/orochi/static/css/jstree/32px.png b/orochi/static/css/jstree/32px.png deleted file mode 100644 index ac74418d2843d0233fc67c04a59462caa82bd860..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8740 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 diff --git a/orochi/static/css/jstree/40px.png b/orochi/static/css/jstree/40px.png deleted file mode 100644 index 29273260075f1654bb86a9e3f42c3f32ab5a2d23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6055 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 B1Y7_B diff --git a/orochi/static/css/jstree/style.min.css b/orochi/static/css/jstree/style.min.css deleted file mode 100644 index 3223b65b..00000000 --- a/orochi/static/css/jstree/style.min.css +++ /dev/null @@ -1 +0,0 @@ -.jstree-node,.jstree-children,.jstree-container-ul{display:block;margin:0;padding:0;list-style-type:none;list-style-image:none}.jstree-node{white-space:nowrap}.jstree-anchor{display:inline-block;color:black;white-space:nowrap;padding:0 4px 0 1px;margin:0;vertical-align:top}.jstree-anchor:focus{outline:0}.jstree-anchor,.jstree-anchor:link,.jstree-anchor:visited,.jstree-anchor:hover,.jstree-anchor:active{text-decoration:none;color:inherit}.jstree-icon{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-icon:empty{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-ocl{cursor:pointer}.jstree-leaf>.jstree-ocl{cursor:default}.jstree .jstree-open>.jstree-children{display:block}.jstree .jstree-closed>.jstree-children,.jstree .jstree-leaf>.jstree-children{display:none}.jstree-anchor>.jstree-themeicon{margin-right:2px}.jstree-no-icons .jstree-themeicon,.jstree-anchor>.jstree-themeicon-hidden{display:none}.jstree-hidden,.jstree-node.jstree-hidden{display:none}.jstree-rtl .jstree-anchor{padding:0 1px 0 4px}.jstree-rtl .jstree-anchor>.jstree-themeicon{margin-left:2px;margin-right:0}.jstree-rtl .jstree-node{margin-left:0}.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-wholerow-ul{position:relative;display:inline-block;min-width:100%}.jstree-wholerow-ul .jstree-leaf>.jstree-ocl{cursor:pointer}.jstree-wholerow-ul .jstree-anchor,.jstree-wholerow-ul .jstree-icon{position:relative}.jstree-wholerow-ul .jstree-wholerow{width:100%;cursor:pointer;position:absolute;left:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jstree-contextmenu .jstree-anchor{-webkit-user-select:none;-webkit-touch-callout:none;user-select:none}.vakata-context{display:none}.vakata-context,.vakata-context ul{margin:0;padding:2px;position:absolute;background:#f5f5f5;border:1px solid #979797;box-shadow:2px 2px 2px #999999}.vakata-context ul{list-style:none;left:100%;margin-top:-2.7em;margin-left:-4px}.vakata-context .vakata-context-right ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context li{list-style:none}.vakata-context li>a{display:block;padding:0 2em 0 2em;text-decoration:none;width:auto;color:black;white-space:nowrap;line-height:2.4em;text-shadow:1px 1px 0 white;border-radius:1px}.vakata-context li>a:hover{position:relative;background-color:#e8eff7;box-shadow:0 0 2px #0a6aa1}.vakata-context li>a.vakata-context-parent{background-image:url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw==");background-position:right center;background-repeat:no-repeat}.vakata-context li>a:focus{outline:0}.vakata-context .vakata-context-no-icons{margin-left:0}.vakata-context .vakata-context-hover>a{position:relative;background-color:#e8eff7;box-shadow:0 0 2px #0a6aa1}.vakata-context .vakata-context-separator>a,.vakata-context .vakata-context-separator>a:hover{background:white;border:0;border-top:1px solid #e2e3e3;height:1px;min-height:1px;max-height:1px;padding:0;margin:0 0 0 2.4em;border-left:1px solid #e0e0e0;text-shadow:0 0 0 transparent;box-shadow:0 0 0 transparent;border-radius:0}.vakata-context .vakata-contextmenu-disabled a,.vakata-context .vakata-contextmenu-disabled a:hover{color:silver;background-color:transparent;border:0;box-shadow:0 0 0}.vakata-context .vakata-contextmenu-disabled>a>i{filter:grayscale(100%)}.vakata-context li>a>i{text-decoration:none;display:inline-block;width:2.4em;height:2.4em;background:transparent;margin:0 0 0 -2em;vertical-align:top;text-align:center;line-height:2.4em}.vakata-context li>a>i:empty{width:2.4em;line-height:2.4em}.vakata-context li>a .vakata-contextmenu-sep{display:inline-block;width:1px;height:2.4em;background:white;margin:0 .5em 0 0;border-left:1px solid #e2e3e3}.vakata-context .vakata-contextmenu-shortcut{font-size:.8em;color:silver;opacity:.5;display:none}.vakata-context-rtl ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context-rtl li>a.vakata-context-parent{background-image:url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7");background-position:left center;background-repeat:no-repeat}.vakata-context-rtl .vakata-context-separator>a{margin:0 2.4em 0 0;border-left:0;border-right:1px solid #e2e3e3}.vakata-context-rtl .vakata-context-left ul{right:auto;left:100%;margin-left:-4px;margin-right:auto}.vakata-context-rtl li>a>i{margin:0 -2em 0 0}.vakata-context-rtl li>a .vakata-contextmenu-sep{margin:0 0 0 .5em;border-left-color:white;background:#e2e3e3}#jstree-marker{position:absolute;top:0;left:0;margin:-5px 0 0 0;padding:0;border-right:0;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid;width:0;height:0;font-size:0;line-height:0}#jstree-dnd{line-height:16px;margin:0;padding:4px}#jstree-dnd .jstree-icon,#jstree-dnd .jstree-copy{display:inline-block;text-decoration:none;margin:0 2px 0 0;padding:0;width:16px;height:16px}#jstree-dnd .jstree-ok{background:green}#jstree-dnd .jstree-er{background:red}#jstree-dnd .jstree-copy{margin:0 2px 0 2px}.jstree-default .jstree-node,.jstree-default .jstree-icon{background-repeat:no-repeat;background-color:transparent}.jstree-default .jstree-anchor,.jstree-default .jstree-animated,.jstree-default .jstree-wholerow{transition:background-color .15s,box-shadow .15s}.jstree-default .jstree-hovered{background:#e7f4f9;border-radius:2px;box-shadow:inset 0 0 1px #cccccc}.jstree-default .jstree-context{background:#e7f4f9;border-radius:2px;box-shadow:inset 0 0 1px #cccccc}.jstree-default .jstree-clicked{background:#beebff;border-radius:2px;box-shadow:inset 0 0 1px #999999}.jstree-default .jstree-no-icons .jstree-anchor>.jstree-themeicon{display:none}.jstree-default .jstree-disabled{background:transparent;color:#666666}.jstree-default .jstree-disabled.jstree-hovered{background:transparent;box-shadow:none}.jstree-default .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default .jstree-disabled>.jstree-icon{opacity:.8;filter:url("data:image/svg+xml;utf8,#jstree-grayscale");filter:gray;-webkit-filter:grayscale(100%)}.jstree-default .jstree-search{font-style:italic;color:#8b0000;font-weight:bold}.jstree-default .jstree-no-checkboxes .jstree-checkbox{display:none !important}.jstree-default.jstree-checkbox-no-clicked .jstree-clicked{background:transparent;box-shadow:none}.jstree-default.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered{background:#e7f4f9}.jstree-default.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked{background:transparent}.jstree-default.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered{background:#e7f4f9}.jstree-default>.jstree-striped{min-width:100%;display:inline-block;background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==") left top repeat}.jstree-default>.jstree-wholerow-ul .jstree-hovered,.jstree-default>.jstree-wholerow-ul .jstree-clicked{background:transparent;box-shadow:none;border-radius:0}.jstree-default .jstree-wholerow{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.jstree-default .jstree-wholerow-hovered{background:#e7f4f9}.jstree-default .jstree-wholerow-clicked{background:#beebff;background:-webkit-linear-gradient(top, #beebff 0%, #a8e4ff 100%);background:linear-gradient(to bottom, #beebff 0%, #a8e4ff 100%)}.jstree-default .jstree-node{min-height:24px;line-height:24px;margin-left:24px;min-width:24px}.jstree-default .jstree-anchor{line-height:24px;height:24px}.jstree-default .jstree-icon{width:24px;height:24px;line-height:24px}.jstree-default .jstree-icon:empty{width:24px;height:24px;line-height:24px}.jstree-default.jstree-rtl .jstree-node{margin-right:24px}.jstree-default .jstree-wholerow{height:24px}.jstree-default .jstree-node,.jstree-default .jstree-icon{background-image:url("32px.png")}.jstree-default .jstree-node{background-position:-292px -4px;background-repeat:repeat-y}.jstree-default .jstree-last{background-image:none}.jstree-default .jstree-open>.jstree-ocl{background-position:-132px -4px}.jstree-default .jstree-closed>.jstree-ocl{background-position:-100px -4px}.jstree-default .jstree-leaf>.jstree-ocl{background-position:-68px -4px}.jstree-default .jstree-themeicon{background-position:-260px -4px}.jstree-default>.jstree-no-dots .jstree-node,.jstree-default>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -4px}.jstree-default>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -4px}.jstree-default .jstree-disabled{background:transparent}.jstree-default .jstree-disabled.jstree-hovered{background:transparent}.jstree-default .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default .jstree-checkbox{background-position:-164px -4px}.jstree-default .jstree-checkbox:hover{background-position:-164px -36px}.jstree-default.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default .jstree-checked>.jstree-checkbox{background-position:-228px -4px}.jstree-default.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default .jstree-checked>.jstree-checkbox:hover{background-position:-228px -36px}.jstree-default .jstree-anchor>.jstree-undetermined{background-position:-196px -4px}.jstree-default .jstree-anchor>.jstree-undetermined:hover{background-position:-196px -36px}.jstree-default .jstree-checkbox-disabled{opacity:.8;filter:url("data:image/svg+xml;utf8,#jstree-grayscale");filter:gray;-webkit-filter:grayscale(100%)}.jstree-default>.jstree-striped{background-size:auto 48px}.jstree-default.jstree-rtl .jstree-node{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");background-position:100% 1px;background-repeat:repeat-y}.jstree-default.jstree-rtl .jstree-last{background-image:none}.jstree-default.jstree-rtl .jstree-open>.jstree-ocl{background-position:-132px -36px}.jstree-default.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-100px -36px}.jstree-default.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-68px -36px}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -36px}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -36px}.jstree-default .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url("throbber.gif") center center no-repeat}.jstree-default .jstree-file{background:url("32px.png") -100px -68px no-repeat}.jstree-default .jstree-folder{background:url("32px.png") -260px -4px no-repeat}.jstree-default>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default{line-height:24px;padding:0 4px}#jstree-dnd.jstree-default .jstree-ok,#jstree-dnd.jstree-default .jstree-er{background-image:url("32px.png");background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default i{background:transparent;width:24px;height:24px;line-height:24px}#jstree-dnd.jstree-default .jstree-ok{background-position:-4px -68px}#jstree-dnd.jstree-default .jstree-er{background-position:-36px -68px}.jstree-default .jstree-ellipsis{overflow:hidden}.jstree-default .jstree-ellipsis .jstree-anchor{width:calc(100% - 24px + 5px);text-overflow:ellipsis;overflow:hidden}.jstree-default.jstree-rtl .jstree-node{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==")}.jstree-default.jstree-rtl .jstree-last{background-image:none}.jstree-default-small .jstree-node{min-height:18px;line-height:18px;margin-left:18px;min-width:18px}.jstree-default-small .jstree-anchor{line-height:18px;height:18px}.jstree-default-small .jstree-icon{width:18px;height:18px;line-height:18px}.jstree-default-small .jstree-icon:empty{width:18px;height:18px;line-height:18px}.jstree-default-small.jstree-rtl .jstree-node{margin-right:18px}.jstree-default-small .jstree-wholerow{height:18px}.jstree-default-small .jstree-node,.jstree-default-small .jstree-icon{background-image:url("32px.png")}.jstree-default-small .jstree-node{background-position:-295px -7px;background-repeat:repeat-y}.jstree-default-small .jstree-last{background-image:none}.jstree-default-small .jstree-open>.jstree-ocl{background-position:-135px -7px}.jstree-default-small .jstree-closed>.jstree-ocl{background-position:-103px -7px}.jstree-default-small .jstree-leaf>.jstree-ocl{background-position:-71px -7px}.jstree-default-small .jstree-themeicon{background-position:-263px -7px}.jstree-default-small>.jstree-no-dots .jstree-node,.jstree-default-small>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default-small>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -7px}.jstree-default-small>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -7px}.jstree-default-small .jstree-disabled{background:transparent}.jstree-default-small .jstree-disabled.jstree-hovered{background:transparent}.jstree-default-small .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-small .jstree-checkbox{background-position:-167px -7px}.jstree-default-small .jstree-checkbox:hover{background-position:-167px -39px}.jstree-default-small.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-small .jstree-checked>.jstree-checkbox{background-position:-231px -7px}.jstree-default-small.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-small .jstree-checked>.jstree-checkbox:hover{background-position:-231px -39px}.jstree-default-small .jstree-anchor>.jstree-undetermined{background-position:-199px -7px}.jstree-default-small .jstree-anchor>.jstree-undetermined:hover{background-position:-199px -39px}.jstree-default-small .jstree-checkbox-disabled{opacity:.8;filter:url("data:image/svg+xml;utf8,#jstree-grayscale");filter:gray;-webkit-filter:grayscale(100%)}.jstree-default-small>.jstree-striped{background-size:auto 36px}.jstree-default-small.jstree-rtl .jstree-node{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");background-position:100% 1px;background-repeat:repeat-y}.jstree-default-small.jstree-rtl .jstree-last{background-image:none}.jstree-default-small.jstree-rtl .jstree-open>.jstree-ocl{background-position:-135px -39px}.jstree-default-small.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-103px -39px}.jstree-default-small.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-71px -39px}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -39px}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -39px}.jstree-default-small .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-small>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url("throbber.gif") center center no-repeat}.jstree-default-small .jstree-file{background:url("32px.png") -103px -71px no-repeat}.jstree-default-small .jstree-folder{background:url("32px.png") -263px -7px no-repeat}.jstree-default-small>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default-small{line-height:18px;padding:0 4px}#jstree-dnd.jstree-default-small .jstree-ok,#jstree-dnd.jstree-default-small .jstree-er{background-image:url("32px.png");background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default-small i{background:transparent;width:18px;height:18px;line-height:18px}#jstree-dnd.jstree-default-small .jstree-ok{background-position:-7px -71px}#jstree-dnd.jstree-default-small .jstree-er{background-position:-39px -71px}.jstree-default-small .jstree-ellipsis{overflow:hidden}.jstree-default-small .jstree-ellipsis .jstree-anchor{width:calc(100% - 18px + 5px);text-overflow:ellipsis;overflow:hidden}.jstree-default-small.jstree-rtl .jstree-node{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==")}.jstree-default-small.jstree-rtl .jstree-last{background-image:none}.jstree-default-large .jstree-node{min-height:32px;line-height:32px;margin-left:32px;min-width:32px}.jstree-default-large .jstree-anchor{line-height:32px;height:32px}.jstree-default-large .jstree-icon{width:32px;height:32px;line-height:32px}.jstree-default-large .jstree-icon:empty{width:32px;height:32px;line-height:32px}.jstree-default-large.jstree-rtl .jstree-node{margin-right:32px}.jstree-default-large .jstree-wholerow{height:32px}.jstree-default-large .jstree-node,.jstree-default-large .jstree-icon{background-image:url("32px.png")}.jstree-default-large .jstree-node{background-position:-288px 0;background-repeat:repeat-y}.jstree-default-large .jstree-last{background-image:none}.jstree-default-large .jstree-open>.jstree-ocl{background-position:-128px 0}.jstree-default-large .jstree-closed>.jstree-ocl{background-position:-96px 0}.jstree-default-large .jstree-leaf>.jstree-ocl{background-position:-64px 0}.jstree-default-large .jstree-themeicon{background-position:-256px 0}.jstree-default-large>.jstree-no-dots .jstree-node,.jstree-default-large>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default-large>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px 0}.jstree-default-large>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 0}.jstree-default-large .jstree-disabled{background:transparent}.jstree-default-large .jstree-disabled.jstree-hovered{background:transparent}.jstree-default-large .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-large .jstree-checkbox{background-position:-160px 0}.jstree-default-large .jstree-checkbox:hover{background-position:-160px -32px}.jstree-default-large.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-large .jstree-checked>.jstree-checkbox{background-position:-224px 0}.jstree-default-large.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-large .jstree-checked>.jstree-checkbox:hover{background-position:-224px -32px}.jstree-default-large .jstree-anchor>.jstree-undetermined{background-position:-192px 0}.jstree-default-large .jstree-anchor>.jstree-undetermined:hover{background-position:-192px -32px}.jstree-default-large .jstree-checkbox-disabled{opacity:.8;filter:url("data:image/svg+xml;utf8,#jstree-grayscale");filter:gray;-webkit-filter:grayscale(100%)}.jstree-default-large>.jstree-striped{background-size:auto 64px}.jstree-default-large.jstree-rtl .jstree-node{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==");background-position:100% 1px;background-repeat:repeat-y}.jstree-default-large.jstree-rtl .jstree-last{background-image:none}.jstree-default-large.jstree-rtl .jstree-open>.jstree-ocl{background-position:-128px -32px}.jstree-default-large.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-96px -32px}.jstree-default-large.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-64px -32px}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px -32px}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 -32px}.jstree-default-large .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-large>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url("throbber.gif") center center no-repeat}.jstree-default-large .jstree-file{background:url("32px.png") -96px -64px no-repeat}.jstree-default-large .jstree-folder{background:url("32px.png") -256px 0 no-repeat}.jstree-default-large>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}#jstree-dnd.jstree-default-large{line-height:32px;padding:0 4px}#jstree-dnd.jstree-default-large .jstree-ok,#jstree-dnd.jstree-default-large .jstree-er{background-image:url("32px.png");background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default-large i{background:transparent;width:32px;height:32px;line-height:32px}#jstree-dnd.jstree-default-large .jstree-ok{background-position:0 -64px}#jstree-dnd.jstree-default-large .jstree-er{background-position:-32px -64px}.jstree-default-large .jstree-ellipsis{overflow:hidden}.jstree-default-large .jstree-ellipsis .jstree-anchor{width:calc(100% - 32px + 5px);text-overflow:ellipsis;overflow:hidden}.jstree-default-large.jstree-rtl .jstree-node{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==")}.jstree-default-large.jstree-rtl .jstree-last{background-image:none}@media (max-width:768px){#jstree-dnd.jstree-dnd-responsive{line-height:40px;font-weight:bold;font-size:1.1em;text-shadow:1px 1px white}#jstree-dnd.jstree-dnd-responsive>i{background:transparent;width:40px;height:40px}#jstree-dnd.jstree-dnd-responsive>.jstree-ok{background-image:url("40px.png");background-position:0 -200px;background-size:120px 240px}#jstree-dnd.jstree-dnd-responsive>.jstree-er{background-image:url("40px.png");background-position:-40px -200px;background-size:120px 240px}#jstree-marker.jstree-dnd-responsive{border-left-width:10px;border-top-width:10px;border-bottom-width:10px;margin-top:-10px}}@media (max-width:768px){.jstree-default-responsive .jstree-icon{background-image:url("40px.png")}.jstree-default-responsive .jstree-node,.jstree-default-responsive .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default-responsive .jstree-node{min-height:40px;line-height:40px;margin-left:40px;min-width:40px;white-space:nowrap}.jstree-default-responsive .jstree-anchor{line-height:40px;height:40px}.jstree-default-responsive .jstree-icon,.jstree-default-responsive .jstree-icon:empty{width:40px;height:40px;line-height:40px}.jstree-default-responsive>.jstree-container-ul>.jstree-node{margin-left:0}.jstree-default-responsive.jstree-rtl .jstree-node{margin-left:0;margin-right:40px;background:transparent}.jstree-default-responsive.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-default-responsive .jstree-ocl,.jstree-default-responsive .jstree-themeicon,.jstree-default-responsive .jstree-checkbox{background-size:120px 240px}.jstree-default-responsive .jstree-leaf>.jstree-ocl,.jstree-default-responsive.jstree-rtl .jstree-leaf>.jstree-ocl{background:transparent}.jstree-default-responsive .jstree-open>.jstree-ocl{background-position:0 0 !important}.jstree-default-responsive .jstree-closed>.jstree-ocl{background-position:0 -40px !important}.jstree-default-responsive.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-40px 0 !important}.jstree-default-responsive .jstree-themeicon{background-position:-40px -40px}.jstree-default-responsive .jstree-checkbox,.jstree-default-responsive .jstree-checkbox:hover{background-position:-40px -80px}.jstree-default-responsive.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox,.jstree-default-responsive.jstree-checkbox-selection .jstree-clicked>.jstree-checkbox:hover,.jstree-default-responsive .jstree-checked>.jstree-checkbox,.jstree-default-responsive .jstree-checked>.jstree-checkbox:hover{background-position:0 -80px}.jstree-default-responsive .jstree-anchor>.jstree-undetermined,.jstree-default-responsive .jstree-anchor>.jstree-undetermined:hover{background-position:0 -120px}.jstree-default-responsive .jstree-anchor{font-weight:bold;font-size:1.1em;text-shadow:1px 1px white}.jstree-default-responsive>.jstree-striped{background:transparent}.jstree-default-responsive .jstree-wholerow{border-top:1px solid rgba(255,255,255,0.7);border-bottom:1px solid rgba(64,64,64,0.2);background:#ebebeb;height:40px}.jstree-default-responsive .jstree-wholerow-hovered{background:#e7f4f9}.jstree-default-responsive .jstree-wholerow-clicked{background:#beebff}.jstree-default-responsive .jstree-children .jstree-last>.jstree-wholerow{box-shadow:inset 0 -6px 3px -5px #666666}.jstree-default-responsive .jstree-children .jstree-open>.jstree-wholerow{box-shadow:inset 0 6px 3px -5px #666666;border-top:0}.jstree-default-responsive .jstree-children .jstree-open+.jstree-open{box-shadow:none}.jstree-default-responsive .jstree-node,.jstree-default-responsive .jstree-icon,.jstree-default-responsive .jstree-node>.jstree-ocl,.jstree-default-responsive .jstree-themeicon,.jstree-default-responsive .jstree-checkbox{background-image:url("40px.png");background-size:120px 240px}.jstree-default-responsive .jstree-node{background-position:-80px 0;background-repeat:repeat-y}.jstree-default-responsive .jstree-last{background-image:none}.jstree-default-responsive .jstree-leaf>.jstree-ocl{background-position:-40px -120px}.jstree-default-responsive .jstree-last>.jstree-ocl{background-position:-40px -160px}.jstree-default-responsive .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-responsive .jstree-file{background:url("40px.png") 0 -160px no-repeat;background-size:120px 240px}.jstree-default-responsive .jstree-folder{background:url("40px.png") -40px -40px no-repeat;background-size:120px 240px}.jstree-default-responsive>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0}} diff --git a/orochi/static/css/jstree/throbber.gif b/orochi/static/css/jstree/throbber.gif deleted file mode 100644 index 5b33f7e54f4e55b6b8774d86d96895db9af044b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1849 zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw diff --git a/orochi/static/css/style.css b/orochi/static/css/style.css index 5b908ac8..55482b61 100644 --- a/orochi/static/css/style.css +++ b/orochi/static/css/style.css @@ -26,7 +26,10 @@ a.navbar-brand { } .list-group-item { - background-color: rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important; + background-color: rgba( + var(--bs-tertiary-bg-rgb), + var(--bs-bg-opacity) + ) !important; } /******************************************************** @@ -124,13 +127,12 @@ main { transform: rotate(45deg); } - /******************************************************** DUMP MENU ICONS ********************************************************/ -.download-index{ - color:#440b5d; +.download-index { + color: #440b5d; } .error-index:hover, @@ -201,7 +203,6 @@ ul.nested-list li.list-group-item { padding-top: 10px; } - /******************************************************** TABLE ********************************************************/ @@ -210,14 +211,6 @@ ul.nested-list li.list-group-item { overflow-x: hidden; } -/******************************************************** - JSTREE -********************************************************/ - -.jstree-table-wrapper.demo { - line-height: 1.75; -} - /******************************************************** MAKE SVG ON BUTTON FIRE CLICK ********************************************************/ @@ -237,14 +230,14 @@ ul.nested-list li.list-group-item { /******************************************************** SMALLER TEXT IN DIALOG INFO ********************************************************/ -.small-dlg{ +.small-dlg { font-size: small; } /******************************************************** SINGLE CHAR PADDING FOR HEX VIEW ********************************************************/ -.singlechar{ +.singlechar { padding-left: 2px; padding-right: 2px; display: inline-block; @@ -254,17 +247,38 @@ ul.nested-list li.list-group-item { /******************************************************** ADDITIONAL DATATABLES BUTTONS ********************************************************/ -.goto input, .next input{ +.goto input, +.next input { display: inline-block; width: auto; margin-left: 0.5em; } -.goto label, .next label{ +.goto label, +.next label { font-weight: normal; text-align: left; white-space: nowrap; } -.goto, div.next, .dataTables_length{ +.goto, +div.next, +.dataTables_length { float: left; margin-left: 50px; } + +/******************************************************** + FIX ICON +********************************************************/ +.wb-icon { + padding-left: 2px; + padding-right: 2px; +} + +main.view { + height: 800px; + overflow: hidden; +} + +div.wunderbaum { + height: 95%; +} diff --git a/orochi/static/css/wunderbaum/wunderbaum.css b/orochi/static/css/wunderbaum/wunderbaum.css new file mode 100644 index 00000000..0547b56c --- /dev/null +++ b/orochi/static/css/wunderbaum/wunderbaum.css @@ -0,0 +1,701 @@ +@charset "UTF-8"; +/*! + * Wunderbaum style sheet (generated from wunderbaum.scss) + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * @VERSION, @DATE (https://github.com/mar10/wunderbaum) + */ +:root, +:host { + --wb-font-stack: Helvetica, sans-serif; + --wb-error-color: #b5373b; + --wb-node-text-color: #56534c; + --wb-border-color: #56534c; + --wb-bg-highlight-color: #26a0da; + --wb-header-color: #dedede; + --wb-background-color: #ffffff; + --wb-alternate-row-color: #f7f7f7; + --wb-alternate-row-color-hover: #f3f3f3; + --wb-focus-border-color: #275dc5; + --wb-drop-source-color: #d3d2ce; + --wb-drop-target-color: #d4ecf8; + --wb-dim-color: #8c877c; + --wb-error-background-color: #f5ddde; + --wb-hover-color: #f7fcfe; + --wb-hover-border-color: #f7fcfe; + --wb-grid-color: #dedede; + --wb-active-color: #e5f3fb; + --wb-active-cell-color: #7dc6e9; + --wb-active-border-color: #70c0e7; + --wb-active-hover-color: #dceff8; + --wb-active-hover-border-color: #26a0da; + --wb-active-column-color: #f7fcfe; + --wb-active-header-column-color: #c5c5c5; + --wb-active-color-grayscale: #f0f0f0; + --wb-active-border-color-grayscale: #acacac; + --wb-active-hover-color-grayscale: #eaeaea; + --wb-active-cell-color-grayscale: #b3b3b3; + --wb-grid-color-grayscale: #dedede; + --wb-filter-dim-color: #dedede; + --wb-filter-submatch-color: #868581; + --wb-row-outer-height: 22px; + --wb-row-inner-height: 20px; + --wb-row-padding-y: 1px; + --wb-col-padding-x: 2px; + --wb-icon-outer-height: 20px; + --wb-icon-outer-width: 20px; + --wb-icon-height: 16px; + --wb-icon-width: 16px; + --wb-icon-padding-y: 2px; + --wb-icon-padding-x: 2px; + --wb-header-height: 22px; +} + +div.wunderbaum * { + box-sizing: border-box; +} + +div.wunderbaum { + height: 100%; + min-height: 4px; + background-color: var(--wb-background-color); + margin: 0; + padding: 0; + font-family: var(--wb-font-stack); + font-size: 14px; + color: var(--wb-node-text-color); + border: 2px solid var(--wb-border-color); + border-radius: 4px; + background-clip: content-box; + overflow-x: auto; + overflow-y: scroll; + /* --- FIXED-COLUMN --- */ + /* Fixed column must be opaque, i.e. have the bg color set. */ + /* --- GRID --- */ + /* --- FILTER --- */ + /* --- DND --- */ + /* --- SPECIAL EFFECTS --- */ + /* Colorize indentation levels. */ + /* Fade out expanders, when container is not hovered or active */ + /* Skeleton */ + /* Auto-hide checkboxes unless selected or hovered */ +} +div.wunderbaum:focus, +div.wunderbaum:focus-within { + border-color: var(--wb-focus-border-color); +} +div.wunderbaum.wb-disabled { + opacity: 0.7; + pointer-events: none; +} +div.wunderbaum div.wb-list-container { + position: relative; + min-height: 4px; +} +div.wunderbaum div.wb-header { + position: sticky; + top: 0; + z-index: 2; +} +div.wunderbaum div.wb-header, +div.wunderbaum div.wb-list-container { + overflow: unset; +} +div.wunderbaum div.wb-row { + position: absolute; + width: 100%; + height: var(--wb-row-outer-height); + line-height: var(--wb-row-outer-height); + border: 1px solid transparent; +} +div.wunderbaum.wb-fixed-col span.wb-col:first-of-type { + position: sticky; + left: 0; + z-index: 1; + background-color: var(--wb-background-color); +} +div.wunderbaum.wb-fixed-col div.wb-header span.wb-col:first-of-type { + background-color: var(--wb-header-color); +} +div.wunderbaum.wb-fixed-col + div.wb-node-list + div.wb-row.wb-active + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col + div.wb-node-list + div.wb-row.wb-selected + span.wb-col:first-of-type { + background-color: var(--wb-active-color); +} +div.wunderbaum.wb-fixed-col + div.wb-node-list + div.wb-row.wb-active:hover + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col + div.wb-node-list + div.wb-row.wb-selected:hover + span.wb-col:first-of-type { + background-color: var(--wb-active-hover-color); +} +div.wunderbaum.wb-fixed-col + div.wb-node-list + div.wb-row:hover + span.wb-col:first-of-type { + background-color: var(--wb-hover-color); +} +div.wunderbaum.wb-fixed-col:not(:focus-within) + div.wb-node-list + div.wb-row.wb-active + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col:not(:focus-within) + div.wb-node-list + div.wb-row.wb-selected + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col:not(:focus) + div.wb-node-list + div.wb-row.wb-active + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col:not(:focus) + div.wb-node-list + div.wb-row.wb-selected + span.wb-col:first-of-type { + background-color: var(--wb-active-color-grayscale); + border-color: var(--wb-active-border-color-grayscale); +} +div.wunderbaum.wb-fixed-col:not(:focus-within) + div.wb-node-list + div.wb-row.wb-active + span.wb-col:first-of-type:hover + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col:not(:focus-within) + div.wb-node-list + div.wb-row.wb-selected + span.wb-col:first-of-type:hover + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col:not(:focus) + div.wb-node-list + div.wb-row.wb-active + span.wb-col:first-of-type:hover + span.wb-col:first-of-type, +div.wunderbaum.wb-fixed-col:not(:focus) + div.wb-node-list + div.wb-row.wb-selected + span.wb-col:first-of-type:hover + span.wb-col:first-of-type { + background-color: var(--wb-active-hover-color-grayscale); +} +div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-active, +div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-selected, +div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-active, +div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-selected { + background-color: var(--wb-active-color-grayscale); + border-color: var(--wb-active-border-color-grayscale); +} +div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-active:hover, +div.wunderbaum:not(:focus-within) div.wb-node-list div.wb-row.wb-selected:hover, +div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-active:hover, +div.wunderbaum:not(:focus) div.wb-node-list div.wb-row.wb-selected:hover { + background-color: var(--wb-active-hover-color-grayscale); +} +div.wunderbaum.wb-alternate + div.wb-node-list + div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected) { + background-color: var(--wb-alternate-row-color); +} +div.wunderbaum.wb-alternate + div.wb-node-list + div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected):hover { + background-color: var(--wb-alternate-row-color-hover); +} +div.wunderbaum div.wb-node-list div.wb-row:hover { + background-color: var(--wb-hover-color); +} +div.wunderbaum div.wb-node-list div.wb-row.wb-active, +div.wunderbaum div.wb-node-list div.wb-row.wb-selected { + background-color: var(--wb-active-color); +} +div.wunderbaum div.wb-node-list div.wb-row.wb-active:hover, +div.wunderbaum div.wb-node-list div.wb-row.wb-selected:hover { + background-color: var(--wb-active-hover-color); +} +div.wunderbaum div.wb-node-list div.wb-row.wb-focus:not(.wb-active) { + border-style: dotted; + border-color: var(--wb-active-border-color); +} +div.wunderbaum div.wb-node-list div.wb-row.wb-active { + border-style: solid; + border-color: var(--wb-active-border-color); +} +div.wunderbaum div.wb-node-list div.wb-row.wb-active:hover { + border-color: var(--wb-active-hover-border-color); +} +div.wunderbaum div.wb-node-list div.wb-row.wb-loading { + font-style: italic; +} +div.wunderbaum div.wb-node-list div.wb-row.wb-busy, +div.wunderbaum div.wb-node-list div.wb-row i.wb-busy, +div.wunderbaum div.wb-node-list div.wb-row .wb-col.wb-busy { + font-style: italic; + background: repeating-linear-gradient( + 45deg, + transparent, + transparent 3.88px, + var(--wb-grid-color) 3.88px, + var(--wb-grid-color) 7.78px + ); + animation: wb-busy-animation 2s linear infinite; +} +div.wunderbaum div.wb-node-list div.wb-row.wb-error, +div.wunderbaum div.wb-node-list div.wb-row.wb-status-error { + color: var(--wb-error-color); +} +div.wunderbaum div.wb-header { + position: sticky; + height: var(--wb-header-height); + border-bottom: 1px solid var(--wb-border-color); + padding: 0; + background-color: var(--wb-header-color); +} +div.wunderbaum div.wb-header span.wb-col { + font-weight: bold; + overflow: visible; +} +div.wunderbaum div.wb-header span.wb-col-title { + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +div.wunderbaum div.wb-header span.wb-col-resizer { + position: absolute; + top: 0; + right: -1px; + width: 3px; + border: none; + border-right: 2px solid var(--wb-border-color); + height: 100%; + cursor: col-resize; +} +div.wunderbaum span.wb-col { + position: absolute; + display: inline-block; + overflow: hidden; + height: var(--wb-row-inner-height); + line-height: var(--wb-row-inner-height); + padding: 0 var(--wb-col-padding-x); + border-right: 1px solid var(--wb-grid-color); + white-space: nowrap; +} +div.wunderbaum span.wb-col:last-of-type { + border-right: none; +} +div.wunderbaum span.wb-node { + user-select: none; + /* Fix Bootstrap Icon alignment */ +} +div.wunderbaum span.wb-node i.wb-checkbox, +div.wunderbaum span.wb-node i.wb-expander, +div.wunderbaum span.wb-node i.wb-icon, +div.wunderbaum span.wb-node i.wb-indent { + height: var(--wb-icon-outer-height); + width: var(--wb-icon-outer-width); + padding: var(--wb-icon-padding-y) var(--wb-icon-padding-x); + display: inline-block; +} +div.wunderbaum span.wb-node i.wb-expander, +div.wunderbaum span.wb-node i.wb-icon { + background-repeat: no-repeat; + background-size: contain; +} +div.wunderbaum span.wb-node i.bi::before { + vertical-align: baseline; +} +div.wunderbaum span.wb-node img.wb-icon { + width: var(--wb-icon-width); + height: var(--wb-icon-height); + padding: var(--wb-icon-padding-y) var(--wb-icon-padding-x); +} +div.wunderbaum span.wb-node i.wb-indent::before { + content: " "; +} +div.wunderbaum span.wb-node i.wb-expander.wb-spin, +div.wunderbaum span.wb-node i.wb-icon.wb-spin { + height: unset; + width: unset; + padding: 0 3px; + animation: wb-spin-animation 2s linear infinite; +} +div.wunderbaum span.wb-node span.wb-title { + min-width: 1em; + vertical-align: top; + overflow-x: hidden; + display: inline-block; + white-space: nowrap; + text-overflow: ellipsis; +} +div.wunderbaum.wb-grid div.wb-header div.wb-row span.wb-col:hover { + background-color: var(--wb-active-header-column-color); +} +div.wunderbaum.wb-grid.wb-cell-mode + div.wb-header + div.wb-row + span.wb-col.wb-active { + background-color: var(--wb-active-hover-color); +} +div.wunderbaum.wb-grid div.wb-node-list div.wb-row { + border-bottom-color: var(--wb-grid-color); +} +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row:hover:not(.wb-active):not(.wb-selected) { + background-color: var(--wb-hover-color); +} +div.wunderbaum.wb-grid div.wb-node-list div.wb-row.wb-active { + border-bottom-color: var(--wb-active-border-color); +} +div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col { + border-right: 1px solid var(--wb-grid-color); +} +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + input.wb-input-edit, +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="color"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="date"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="datetime"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="datetime-local"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="email"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="month"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="number"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="password"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="search"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="tel"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="text"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="time"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="url"], +div.wunderbaum.wb-grid + div.wb-node-list + div.wb-row + span.wb-col + > input[type="week"], +div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col > select { + width: 100%; + max-height: var(--wb-row-inner-height); + border: none; +} +div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col > input:focus, +div.wunderbaum.wb-grid div.wb-node-list div.wb-row span.wb-col > select:focus { + border: 1px dashed #70c0e7; +} +div.wunderbaum.wb-grid.wb-cell-mode + div.wb-row:not(.wb-colspan).wb-active + span.wb-col.wb-active { + background-color: var(--wb-active-cell-color-grayscale); +} +div.wunderbaum.wb-grid.wb-cell-mode:focus-within + div.wb-row:not(.wb-colspan):not(.wb-selected) + span.wb-col.wb-active, +div.wunderbaum.wb-grid.wb-cell-mode:focus + div.wb-row:not(.wb-colspan):not(.wb-selected) + span.wb-col.wb-active { + background-color: var(--wb-active-column-color); +} +div.wunderbaum.wb-grid.wb-cell-mode:focus-within + div.wb-row:not(.wb-colspan):not(.wb-selected).wb-active, +div.wunderbaum.wb-grid.wb-cell-mode:focus + div.wb-row:not(.wb-colspan):not(.wb-selected).wb-active { + background-color: var(--wb-active-column-color); +} +div.wunderbaum.wb-grid.wb-cell-mode:focus-within + div.wb-row:not(.wb-colspan):not(.wb-selected).wb-active + span.wb-col.wb-active, +div.wunderbaum.wb-grid.wb-cell-mode:focus + div.wb-row:not(.wb-colspan):not(.wb-selected).wb-active + span.wb-col.wb-active { + background-color: var(--wb-active-cell-color); +} +div.wunderbaum.wb-grid.wb-alternate + div.wb-node-list + div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected) { + background-color: var(--wb-alternate-row-color); +} +div.wunderbaum.wb-grid.wb-alternate + div.wb-node-list + div.wb-row:nth-of-type(even):not(.wb-active):not(.wb-selected):hover { + background-color: var(--wb-alternate-row-color-hover); +} +div.wunderbaum.wb-grid:not(:focus-within) div.wb-node-list div.wb-row, +div.wunderbaum.wb-grid:not(:focus) div.wb-node-list div.wb-row { + border-bottom-color: var(--wb-grid-color-grayscale); +} +div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row, +div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row { + color: var(--wb-filter-dim-color); +} +div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row.wb-submatch, +div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row.wb-submatch { + color: var(--wb-filter-submatch-color); +} +div.wunderbaum.wb-ext-filter-dim div.wb-node-list div.wb-row.wb-match, +div.wunderbaum.wb-ext-filter-hide div.wb-node-list div.wb-row.wb-match { + color: var(--wb-node-text-color); +} +div.wunderbaum div.wb-row.wb-drag-source { + opacity: 0.5; +} +div.wunderbaum div.wb-row.wb-drag-source .wb-node { + background-color: var(--wb-drop-source-color); +} +div.wunderbaum div.wb-row.wb-drop-target { + overflow: visible; +} +div.wunderbaum div.wb-row.wb-drop-target .wb-node { + background-color: var(--wb-drop-target-color); + overflow: visible; +} +div.wunderbaum div.wb-row.wb-drop-target .wb-node .wb-icon { + position: relative; + overflow: visible; +} +div.wunderbaum div.wb-row.wb-drop-target .wb-node .wb-icon::after { + position: absolute; + z-index: 1000; + content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAMAAABA3o1rAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACKUExURe/v9/f39+//7+f35+f/79bW5wgIawwYd97e55Tnpc731rjA2d7350LOY1LWa7Xvvf///wAQcyAze97e773vxnuczgA5pQBCpdb33rXvxu//9whjxgBaxlKU1oOz5ABz3gB73tbn99bW1rXe/wCM9xiU997v/97e3gCc/xil/9bv/wic/+/3/wAAALM9X5QAAAAudFJOU////////////////////////////////////////////////////////////wCCj3NVAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAqUlEQVQoU6WQ2w6CMAxA54agsCHq1HlFBREv/f/fs1tHAoaoiedlbXrWtGXwhV8FNqAXuAi4DwkShmE0cgGIcSwCCgkSkrAxpEonot0DhQxJptFsbnOpdNdgsFh6VtYwyqzTmG+oijDY7hr22E4qY7QybeGQe46nsxP0Wwc3Q1GWl+qKec8MlqKubxX+xzV7tkDuD1+3d+heigT2zGx/hCMUeUj4wL8CwAsW1kqCTugMCwAAAABJRU5ErkJggg==); + left: 0; + top: calc((22px - var(--wb-icon-height)) / 2); +} +div.wunderbaum + div.wb-row.wb-drop-target.wb-drop-before + .wb-node + .wb-icon::after, +div.wunderbaum + div.wb-row.wb-drop-target.wb-drop-after + .wb-node + .wb-icon::after { + content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAQCAMAAACROYkbAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACNUExURe/v9/f39+//7+f35+f/79bW5wgIawwYd97e55Tnpc731rjA2d7350LOY1LWa7Xvvf///wAQcyAze97e773vxgAAAHuczgA5pQBCpdb33rXvxu//9whjxgBaxlKU1oOz5ABz3gB73tbn99bW1rXe/wCM9xiU997v/97e3gCc/xil/9bv/wic/+/3/wAAAParqS4AAAAvdFJOU/////////////////////////////////////////////////////////////8AWqU49wAAAAlwSFlzAAAOwwAADsMBx2+oZAAAALlJREFUOE/FktsSgiAQhglMS8WstKLzQTM77Ps/XguL16I208cFyzB8/LPAYCC/ErARzcCFx23pBgnGfjAxBYhpKDwq3SBB5DeGWCYz0SUDClIkmgeLpV7HMiNDbrbbYbBaWzbaoKTaJiHfQe5oYLA/NBwxTiyVyqTSghYwox4MTmfL5XozgqxjAtODoizv1QPXPXqgKer6WeH9+Iw9XgF5ve15/Q+6/SQSsE+q8yMcocoREgzg3wKAL4vrpBIKREShAAAAAElFTkSuQmCC); + left: 0; + top: calc((22px - var(--wb-icon-height)) / 2 - 11px); +} +div.wunderbaum + div.wb-row.wb-drop-target.wb-drop-after + .wb-node + .wb-icon::after { + top: calc((22px - var(--wb-icon-height)) / 2 + 11px); +} +div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n + 1), +div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n + 1) { + background: rgb(255, 255, 201); +} +div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n + 2), +div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n + 2) { + background: rgb(218, 255, 218); +} +div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n + 3), +div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n + 3) { + background: rgb(255, 217, 254); +} +div.wunderbaum.wb-rainbow i.wb-expander:nth-child(4n + 4), +div.wunderbaum.wb-rainbow i.wb-indent:nth-child(4n + 4) { + background: rgb(204, 250, 250); +} +div.wunderbaum.wb-fade-expander i.wb-expander { + transition: color 1.5s; + color: rgba(86, 83, 76, 0); +} +div.wunderbaum.wb-fade-expander div.wb-row.wb-loading i.wb-expander, +div.wunderbaum.wb-fade-expander:hover i.wb-expander, +div.wunderbaum.wb-fade-expander:focus i.wb-expander, +div.wunderbaum.wb-fade-expander:focus-within i.wb-expander, +div.wunderbaum.wb-fade-expander [class*="wb-statusnode-"] i.wb-expander { + transition: color 0.6s; + color: var(--wb-node-text-color); +} +div.wunderbaum div.wb-row.wb-skeleton span.wb-title, +div.wunderbaum div.wb-row.wb-skeleton i.wb-icon { + animation: wb-skeleton-animation 1s linear infinite alternate; + border-radius: 0.25em; + color: transparent; + opacity: 0.7; +} +div.wunderbaum.wb-checkbox-auto-hide i.wb-checkbox { + visibility: hidden; +} +div.wunderbaum.wb-checkbox-auto-hide .wb-row:hover i.wb-checkbox, +div.wunderbaum.wb-checkbox-auto-hide .wb-row.wb-selected i.wb-checkbox { + visibility: unset; +} +div.wunderbaum.wb-checkbox-auto-hide:focus .wb-row.wb-active i.wb-checkbox, +div.wunderbaum.wb-checkbox-auto-hide:focus-within + .wb-row.wb-active + i.wb-checkbox { + visibility: unset; +} + +/* --- TOOL CLASSES --- */ +.wb-helper-center { + text-align: center; +} + +.wb-helper-disabled { + color: var(--wb-dim-color); +} + +.wb-helper-hidden { + display: none; +} + +.wb-helper-invalid { + color: var(--wb-error-color); +} + +.wb-helper-lazy-expander { + color: var(--wb-bg-highlight-color); +} + +.wb-helper-link { + cursor: pointer; +} + +.wb-no-select { + user-select: none; + -webkit-user-select: none; +} +.wb-no-select span.wb-title { + user-select: contain; + -webkit-user-select: contain; +} + +/* RTL support */ +.wb-helper-start, +.wb-helper-start > input { + text-align: left; +} + +.wb-helper-end, +.wb-helper-end > input { + text-align: right; +} + +.wb-rtl .wb-helper-start, +.wb-rtl .wb-helper-start > input { + text-align: right; +} +.wb-rtl .wb-helper-end, +.wb-rtl .wb-helper-end > input { + text-align: left; +} + +i.wb-icon { + position: relative; +} +i.wb-icon > span.wb-badge { + position: absolute; + display: inline-block; + top: 0; + left: -0.6rem; + color: white; + background-color: var(--wb-bg-highlight-color); + padding: 0.2em 0.3rem 0.1em 0.3rem; + font-size: 60%; + font-weight: 200; + line-height: 1; + text-align: center; + white-space: nowrap; + border-radius: 0.5rem; + pointer-events: none; +} + +/* Class 'wb-tristate' is used to mark checkboxes that should toggle like + * indeterminate -> checked -> unchecked -> indeterminate ... + */ +.wb-col input[type="checkbox"]:indeterminate { + color: var(--wb-dim-color); + background-color: red; +} + +.wb-col input:invalid { + background-color: var(--wb-error-background-color); +} + +.wb-col.wb-invalid { + border: 1px dotted var(--wb-error-color); +} + +@keyframes wb-spin-animation { + 0% { + transform: rotate(0deg); + } + to { + transform: rotate(1turn); + } +} +@keyframes wb-skeleton-animation { + 0% { + background-color: hsl(200, 20%, 70%); + } + 100% { + background-color: hsl(200, 20%, 95%); + } +} +@keyframes wb-busy-animation { + 0% { + background-position: 0 0; + } + 100% { + background-position: 0 22px; + } +} + +/*# sourceMappingURL=wunderbaum.css.map */ diff --git a/orochi/static/css/wunderbaum/wunderbaum.css.map b/orochi/static/css/wunderbaum/wunderbaum.css.map new file mode 100644 index 00000000..56e50b85 --- /dev/null +++ b/orochi/static/css/wunderbaum/wunderbaum.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../src/wunderbaum.scss"],"names":[],"mappings":";AAAA;AAAA;AAAA;AAAA;AAAA;AA2EA;AAAA;EAME;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EAEA;;;AAMF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EAGA;AAsBA;AAuBA;AAwQA;AAoHA;AAwBA;AAgEA;AAEA;AAUA;AAoBA;AAYA;;AAziBA;EAEE;;AAIF;EACE;EACA;;AAGF;EACE;EAEA;;AAMF;EACE;EACA;EACA;;AAGF;AAAA;EAEE;;AAKF;EACE;EACA;EACA;EACA;EACA;;AAMA;EACE;EACA;EACA;EACA;;AAIA;EACE;;AAKF;EAEE;;AAGF;EAEE;;AAGF;EACE;;AAOA;EAEE;EACA;;AAEA;EACE;;AAaN;EAEE;EACA;;AAEA;EACE;;AAON;EACE;;AAEA;EACE;;AAOF;EACE;;AAGF;EAEE;;AAGA;EACE;;AAKJ;EACE;EACA;;AAGF;EAEE;EACA;;AAEA;EAEE;;AAIJ;EACE;;AAGF;AAAA;AAAA;EAGE;EAcA;EASA;;AAGF;EAEE;;AAON;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EAIA;;AAIF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;;AAIJ;EACE;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;AAqBA;;AAhBA;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;;AAGF;AAAA;EAEE;EACA;;AAIF;EACE;;AAGF;EACE;EACA;EACA;;AAMA;EACE;;AAIJ;AAAA;EAEE;EACA;EACA;EACA;;AAGF;EACE;EAEA;EACA;EACA;EACA;EACA;;AAUI;EACE;;AAON;EACE;;AAIJ;EACE;;AAEA;EACE;;AAIF;EACE;;AAGF;EACE;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAgBE;EACA;EACA;;AAGF;AAAA;EAEE;;AAcA;EACE;;AAWJ;EACE;;AAGF;EACE;;AAEA;EACE;;AAON;EACE;;AAEA;EACE;;AAQJ;EACE;;AASJ;EACE;;AAEA;EACE;;AAGF;EACE;;AAcN;EACE;;AAEA;EACE;;AAIJ;EACE;;AAEA;EACE;EACA;;AAGA;EACE;EACA;;AAEA;EAGE;EACA;EAGA;EACA;EACA;;AAgBR;AAAA;EAIE;EACA;EACA;;AAKF;EACE;;AAUE;AAAA;EAEE;;AAFF;AAAA;EAEE;;AAFF;AAAA;EAEE;;AAFF;AAAA;EAEE;;AAOJ;EAIE;EACA;;AAGF;AAAA;EAKE;EACA;;AAMF;AAAA;EAEE;EACA;EACA;EACA;;AAOF;EACE;;AAGF;AAAA;EAEE;;AAKA;EACE;;;AAMR;AAEA;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;;AAQJ;AACA;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAIA;AAAA;EAEE;;AAGF;AAAA;EAEE;;;AAIJ;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;;;AAIJ;AAAA;AAAA;AAMA;EACE;EACA;;;AAGF;EAGE;;;AAGF;EACE;;;AAKF;EACE;IACE;;EAGF;IACE;;;AAIJ;EACE;IACE;;EAGF;IACE;;;AAIJ;EACE;IACE;;EAGF;IACE","file":"wunderbaum.css"} diff --git a/orochi/static/js/jstree/jstree.min.js b/orochi/static/js/jstree/jstree.min.js deleted file mode 100644 index abc88e7f..00000000 --- a/orochi/static/js/jstree/jstree.min.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! jsTree - v3.3.16 - 2023-09-19 - (MIT) */ - -!function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):"undefined"!=typeof module&&module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(E,P){"use strict";if(!E.jstree){var s=0,a=!1,n=!1,o=!1,r=[],e=E("script:last").attr("src"),b=window.document,c=window.setImmediate,i=window.Promise;!c&&i&&(c=function(e,t){i.resolve(t).then(e)}),E.jstree={version:"3.3.16",defaults:{plugins:[]},plugins:{},path:e&&-1!==e.indexOf("/")?e.replace(/\/[^\/]+$/,""):"",idregex:/[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g,root:"#"},E.jstree.create=function(e,i){var r=new E.jstree.core(++s),t=i;return i=E.extend(!0,{},E.jstree.defaults,i),t&&t.plugins&&(i.plugins=t.plugins),E.each(i.plugins,function(e,t){"core"!==e&&(r=r.plugin(t,i[t]))}),E(e).data("jstree",r),r.init(e,i),r},E.jstree.destroy=function(){E(".jstree:jstree").jstree("destroy"),E(b).off(".jstree")},E.jstree.core=function(e){this._id=e,this._cnt=0,this._wrk=null,this._data={core:{themes:{name:!1,dots:!1,icons:!1,ellipsis:!1},selected:[],last_error:{},working:!1,worker_queue:[],focused:null}}},E.jstree.reference=function(t){var i=null,e=null;if(!t||!t.id||t.tagName&&t.nodeType||(t=t.id),!e||!e.length)try{e=E(t)}catch(e){}if(!e||!e.length)try{e=E("#"+t.replace(E.jstree.idregex,"\\$&"))}catch(e){}return e&&e.length&&(e=e.closest(".jstree")).length&&(e=e.data("jstree"))?i=e:E(".jstree").each(function(){var e=E(this).data("jstree");if(e&&e._model.data[t])return i=e,!1}),i},E.fn.jstree=function(i){var r="string"==typeof i,s=Array.prototype.slice.call(arguments,1),a=null;return!(!0===i&&!this.length)&&(this.each(function(){var e=E.jstree.reference(this),t=r&&e?e[i]:null;if(a=r&&t?t.apply(e,s):null,e||r||i!==P&&!E.isPlainObject(i)||E.jstree.create(this,i),null!==(a=e&&!r||!0===i?e||!1:a)&&a!==P)return!1}),null!==a&&a!==P?a:this)},E.expr.pseudos.jstree=E.expr.createPseudo(function(e){return function(e){return E(e).hasClass("jstree")&&E(e).data("jstree")!==P}}),E.jstree.defaults.core={data:!1,strings:!1,check_callback:!1,error:E.noop,animation:200,multiple:!0,themes:{name:!1,url:!1,dir:!1,dots:!0,icons:!0,ellipsis:!1,stripes:!1,variant:!1,responsive:!1},expand_selected_onload:!0,worker:!0,force_text:!1,dblclick_toggle:!0,loaded_state:!1,restore_focus:!0,compute_elements_positions:!1,keyboard:{"ctrl-space":function(e){e.type="click",E(e.currentTarget).trigger(e)},enter:function(e){e.type="click",E(e.currentTarget).trigger(e)},left:function(e){var e;e.preventDefault(),this.is_open(e.currentTarget)?this.close_node(e.currentTarget):(e=this.get_parent(e.currentTarget))&&e.id!==E.jstree.root&&this.get_node(e,!0).children(".jstree-anchor").trigger("focus")},up:function(e){e.preventDefault();var e=this.get_prev_dom(e.currentTarget);e&&e.length&&e.children(".jstree-anchor").trigger("focus")},right:function(e){var e;e.preventDefault(),this.is_closed(e.currentTarget)?this.open_node(e.currentTarget,function(e){this.get_node(e,!0).children(".jstree-anchor").trigger("focus")}):!this.is_open(e.currentTarget)||(e=this.get_node(e.currentTarget,!0).children(".jstree-children")[0])&&E(this._firstChild(e)).children(".jstree-anchor").trigger("focus")},down:function(e){e.preventDefault();var e=this.get_next_dom(e.currentTarget);e&&e.length&&e.children(".jstree-anchor").trigger("focus")},"*":function(e){this.open_all()},home:function(e){e.preventDefault();var e=this._firstChild(this.get_container_ul()[0]);e&&E(e).children(".jstree-anchor").filter(":visible").trigger("focus")},end:function(e){e.preventDefault(),this.element.find(".jstree-anchor").filter(":visible").last().trigger("focus")},f2:function(e){e.preventDefault(),this.edit(e.currentTarget)}},allow_reselect:!1},E.jstree.core.prototype={plugin:function(e,t){var i=E.jstree.plugins[e];return i?(this._data[e]={},i.prototype=this,new i(t,this)):this},init:function(e,t){this._model={data:{},changed:[],force_full_redraw:!1,redraw_timeout:!1,default_state:{loaded:!0,opened:!1,selected:!1,disabled:!1}},this._model.data[E.jstree.root]={id:E.jstree.root,parent:null,parents:[],children:[],children_d:[],state:{loaded:!1}},this.element=E(e).addClass("jstree jstree-"+this._id),this.settings=t,this._data.core.ready=!1,this._data.core.loaded=!1,this._data.core.rtl="rtl"===this.element.css("direction"),this.element[this._data.core.rtl?"addClass":"removeClass"]("jstree-rtl"),this.element.attr("role","tree"),this.settings.core.multiple&&this.element.attr("aria-multiselectable",!0),this.element.attr("tabindex")||this.element.attr("tabindex","0"),this.bind(),this.trigger("init"),this._data.core.original_container_html=this.element.find(" > ul > li").clone(!0),this._data.core.original_container_html.find("li").addBack().contents().filter(function(){return 3===this.nodeType&&(!this.nodeValue||/^\s+$/.test(this.nodeValue))}).remove(),this.element.html(""),this.element.attr("aria-activedescendant","j"+this._id+"_loading"),this._data.core.li_height=this.get_container_ul().children("li").first().outerHeight()||24,this._data.core.node=this._create_prototype_node(),this.trigger("loading"),this.load_node(E.jstree.root)},destroy:function(e){if(this.trigger("destroy"),this._wrk)try{window.URL.revokeObjectURL(this._wrk),this._wrk=null}catch(e){}e||this.element.empty(),this.teardown()},_create_prototype_node:function(){var e=b.createElement("LI"),t,i;return e.setAttribute("role","none"),(t=b.createElement("I")).className="jstree-icon jstree-ocl",t.setAttribute("role","presentation"),e.appendChild(t),(t=b.createElement("A")).className="jstree-anchor",t.setAttribute("href","#"),t.setAttribute("tabindex","-1"),t.setAttribute("role","treeitem"),(i=b.createElement("I")).className="jstree-icon jstree-themeicon",i.setAttribute("role","presentation"),t.appendChild(i),e.appendChild(t),t=i=null,e},_kbevent_to_func:function(e){var t={8:"Backspace",9:"Tab",13:"Enter",19:"Pause",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"Print",45:"Insert",46:"Delete",96:"Numpad0",97:"Numpad1",98:"Numpad2",99:"Numpad3",100:"Numpad4",101:"Numpad5",102:"Numpad6",103:"Numpad7",104:"Numpad8",105:"Numpad9","-13":"NumpadEnter",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"Numlock",145:"Scrolllock",16:"Shift",17:"Ctrl",18:"Alt",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",61:"=",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",107:"+",109:"-",110:".",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",111:"/",106:"*",173:"-"},i=[];if(e.ctrlKey&&i.push("ctrl"),e.altKey&&i.push("alt"),e.shiftKey&&i.push("shift"),i.push(t[e.which]?t[e.which].toLowerCase():e.which),"shift-shift"===(i=i.sort().join("-").toLowerCase())||"ctrl-ctrl"===i||"alt-alt"===i)return null;var r=this.settings.core.keyboard,s,a;for(s in r)if(r.hasOwnProperty(s)&&(a="-"!==(a=s)&&"+"!==a?(a=a.replace("--","-MINUS").replace("+-","-MINUS").replace("++","-PLUS").replace("-+","-PLUS")).split(/-|\+/).sort().join("-").replace("MINUS","-").replace("PLUS","+").toLowerCase():a)===i)return r[s];return null},teardown:function(){this.unbind(),this.element.removeClass("jstree").removeData("jstree").find("[class^='jstree']").addBack().attr("class",function(){return this.className.replace(/jstree[^ ]*|$/gi,"")}),this.element=null},bind:function(){var s="",a=null,t=0;this.element.on("dblclick.jstree",function(e){if(e.target.tagName&&"input"===e.target.tagName.toLowerCase())return!0;if(b.selection&&b.selection.empty)b.selection.empty();else if(window.getSelection){var e=window.getSelection();try{e.removeAllRanges(),e.collapse()}catch(e){}}}).on("mousedown.jstree",function(e){e.target===this.element[0]&&(e.preventDefault(),t=+new Date)}.bind(this)).on("mousedown.jstree",".jstree-ocl",function(e){e.preventDefault()}).on("click.jstree",".jstree-ocl",function(e){this.toggle_node(e.target)}.bind(this)).on("dblclick.jstree",".jstree-anchor",function(e){if(e.target.tagName&&"input"===e.target.tagName.toLowerCase())return!0;this.settings.core.dblclick_toggle&&this.toggle_node(e.target)}.bind(this)).on("click.jstree",".jstree-anchor",function(e){e.preventDefault(),e.currentTarget!==b.activeElement&&E(e.currentTarget).trigger("focus"),this.activate_node(e.currentTarget,e)}.bind(this)).on("keydown.jstree",".jstree-anchor",function(e){if(e.target.tagName&&"input"===e.target.tagName.toLowerCase())return!0;this._data.core.rtl&&(37===e.which?e.which=39:39===e.which&&(e.which=37));var t=this._kbevent_to_func(e);if(t){var e=t.call(this,e);if(!1===e||!0===e)return e}}.bind(this)).on("load_node.jstree",function(e,t){t.status&&(t.node.id!==E.jstree.root||this._data.core.loaded||(this._data.core.loaded=!0,this._firstChild(this.get_container_ul()[0])&&this.element.attr("aria-activedescendant",this._firstChild(this.get_container_ul()[0]).id),this.trigger("loaded")),this._data.core.ready||setTimeout(function(){if(this.element&&!this.get_container_ul().find(".jstree-loading").length){if(this._data.core.ready=!0,this._data.core.selected.length){if(this.settings.core.expand_selected_onload){for(var e=[],t,i,t=0,i=this._data.core.selected.length;t .jstree-anchor").trigger("focus"))}.bind(this)).on("mouseenter.jstree",".jstree-anchor",function(e){this.hover_node(e.currentTarget)}.bind(this)).on("mouseleave.jstree",".jstree-anchor",function(e){this.dehover_node(e.currentTarget)}.bind(this))},unbind:function(){this.element.off(".jstree"),E(b).off(".jstree-"+this._id)},trigger:function(e,t){((t=t||{}).instance=this).element.triggerHandler(e.replace(".jstree","")+".jstree",t)},get_container:function(){return this.element},get_container_ul:function(){return this.element.children(".jstree-children").first()},get_string:function(e){var t=this.settings.core.strings;return E.vakata.is_function(t)?t.call(this,e):t&&t[e]?t[e]:e},_firstChild:function(e){e=e?e.firstChild:null;while(null!==e&&1!==e.nodeType)e=e.nextSibling;return e},_nextSibling:function(e){e=e?e.nextSibling:null;while(null!==e&&1!==e.nodeType)e=e.nextSibling;return e},_previousSibling:function(e){e=e?e.previousSibling:null;while(null!==e&&1!==e.nodeType)e=e.previousSibling;return e},get_node:function(e,t){var i;(e=e&&(e.id||0===e.id)?e.id:e)instanceof E&&e.length&&e[0].id&&(e=e[0].id);try{if(this._model.data[e])e=this._model.data[e];else if("string"==typeof e&&this._model.data[e.replace(/^#/,"")])e=this._model.data[e.replace(/^#/,"")];else if("string"==typeof e&&(i=E("#"+e.replace(E.jstree.idregex,"\\$&"),this.element)).length&&this._model.data[i.closest(".jstree-node").attr("id")])e=this._model.data[i.closest(".jstree-node").attr("id")];else if((i=this.element.find(e)).length&&this._model.data[i.closest(".jstree-node").attr("id")])e=this._model.data[i.closest(".jstree-node").attr("id")];else{if(!(i=this.element.find(e)).length||!i.hasClass("jstree"))return!1;e=this._model.data[E.jstree.root]}return e=t?e.id===E.jstree.root?this.element:E("#"+e.id.replace(E.jstree.idregex,"\\$&"),this.element):e}catch(e){return!1}},get_path:function(e,t,i){if(!(e=e.parents?e:this.get_node(e))||e.id===E.jstree.root||!e.parents)return!1;var r,s,a=[];for(a.push(i?e.id:e.text),r=0,s=e.parents.length;r").html(t),n.text=this.settings.core.force_text?t.text():t.html(),t=e.data(),n.data=t?E.extend(!0,{},t):null,n.state.opened=e.hasClass("jstree-open"),n.state.selected=e.children("a").hasClass("jstree-clicked"),n.state.disabled=e.children("a").hasClass("jstree-disabled"),n.data&&n.data.jstree)for(o in n.data.jstree)n.data.jstree.hasOwnProperty(o)&&(n.state[o]=n.data.jstree[o]);(t=e.children("a").children(".jstree-themeicon")).length&&(n.icon=!t.hasClass("jstree-themeicon-hidden")&&t.attr("rel")),n.state.icon!==P&&(n.icon=n.state.icon),n.icon!==P&&null!==n.icon&&""!==n.icon||(n.icon=!0),t=e.children("ul").children("li");do{d="j"+this._id+"_"+ ++this._cnt}while(a[d]);return n.id=n.li_attr.id?n.li_attr.id.toString():d,t.length?(t.each(function(e,t){r=this._parse_model_from_html(E(t),n.id,i),s=this._model.data[r],n.children.push(r),s.children_d.length&&(n.children_d=n.children_d.concat(s.children_d))}.bind(this)),n.children_d=n.children_d.concat(n.children)):e.hasClass("jstree-closed")&&(n.state.loaded=!1),n.li_attr.class&&(n.li_attr.class=n.li_attr.class.replace("jstree-closed","").replace("jstree-open","")),n.a_attr.class&&(n.a_attr.class=n.a_attr.class.replace("jstree-clicked","").replace("jstree-disabled","")),(a[n.id]=n).state.selected&&this._data.core.selected.push(n.id),n.id},_parse_model_from_flat_json:function(e,t,i){i=i?i.concat():[],t&&i.unshift(t);var r=e.id.toString(),s=this._model.data,a=this._model.default_state,n,o,d,c,l={id:r,text:e.text||"",icon:e.icon===P||e.icon,parent:t,parents:i,children:e.children||[],children_d:e.children_d||[],data:e.data,state:{},li_attr:{id:!1},a_attr:{href:"#"},original:!1};for(n in a)a.hasOwnProperty(n)&&(l.state[n]=a[n]);if(e&&e.data&&e.data.jstree&&e.data.jstree.icon&&(l.icon=e.data.jstree.icon),l.icon!==P&&null!==l.icon&&""!==l.icon||(l.icon=!0),e&&e.data&&(l.data=e.data,e.data.jstree))for(n in e.data.jstree)e.data.jstree.hasOwnProperty(n)&&(l.state[n]=e.data.jstree[n]);if(e&&"object"==typeof e.state)for(n in e.state)e.state.hasOwnProperty(n)&&(l.state[n]=e.state[n]);if(e&&"object"==typeof e.li_attr)for(n in e.li_attr)e.li_attr.hasOwnProperty(n)&&(l.li_attr[n]=e.li_attr[n]);if(l.li_attr.id||(l.li_attr.id=r),e&&"object"==typeof e.a_attr)for(n in e.a_attr)e.a_attr.hasOwnProperty(n)&&(l.a_attr[n]=e.a_attr[n]);for(e&&e.children&&!0===e.children&&(l.state.loaded=!1,l.children=[],l.children_d=[]),n=0,o=(s[l.id]=l).children.length;n
  • "+this.get_string("Loading ...")+"
  • "),this.element.attr("aria-activedescendant","j"+this._id+"_loading")),this.load_node(E.jstree.root,function(e,t){t&&(this.get_container_ul()[0].className=i,this._firstChild(this.get_container_ul()[0])&&this.element.attr("aria-activedescendant",this._firstChild(this.get_container_ul()[0]).id),this.set_state(E.extend(!0,{},this._data.core.state),function(){this.trigger("refresh")})),this._data.core.state=null})},refresh_node:function(t){if(!(t=this.get_node(t))||t.id===E.jstree.root)return!1;var i=[],e=[],r=this._data.core.selected.concat([]);e.push(t.id),!0===t.state.opened&&i.push(t.id),this.get_node(t,!0).find(".jstree-open").each(function(){e.push(this.id),i.push(this.id)}),this._load_nodes(e,function(e){this.open_node(i,!1,0),this.select_node(r),this.trigger("refresh_node",{node:t,nodes:e})}.bind(this),!1,!0)},set_id:function(e,t){if(!(e=this.get_node(e))||e.id===E.jstree.root)return!1;var i,r,s=this._model.data,a=e.id;for(t=t.toString(),s[e.parent].children[E.inArray(e.id,s[e.parent].children)]=t,i=0,r=e.parents.length;ie.children.length&&(i=e.children.length),t.id===P&&(t.id=!0),!this.check("create_node",t,e,i))return this.settings.core.error.call(this,this._data.core.last_error),!1;if(!0===t.id&&delete t.id,!(t=this._parse_model_from_json(t,e.id,e.parents.concat())))return!1;for(a=this.get_node(t),(n=[]).push(t),n=n.concat(a.children_d),this.trigger("model",{nodes:n,parent:e.id}),e.children_d=e.children_d.concat(n),o=0,d=e.parents.length;oh.children.length&&(i=h.children.length),!this.check("move_node",e,h,i,{core:!0,origin:n,is_multi:_&&_._id&&_._id!==this._id,is_foreign:!_||!_._id}))return this.settings.core.error.call(this,this._data.core.last_error),!1;if(e.parent===h.id){for(u=h.children.concat(),-1!==(f=E.inArray(e.id,u))&&(u=E.vakata.array_remove(u,f),ff.children.length&&(i=f.children.length),!this.check("copy_node",e,f,i,{core:!0,origin:n,is_multi:p&&p._id&&p._id!==this._id,is_foreign:!p||!p._id}))return this.settings.core.error.call(this,this._data.core.last_error),!1;if(!(g=p?p.get_json(e,{no_id:!0,no_data:!0,no_state:!0}):e))return!1;if(!0===g.id&&delete g.id,!(g=this._parse_model_from_json(g,f.id,f.parents.concat())))return!1;for(l=this.get_node(g),e&&e.state&&!1===e.state.loaded&&(l.state.loaded=!1),(c=[]).push(g),c=c.concat(l.children_d),this.trigger("model",{nodes:c,parent:f.id}),h=0,_=f.parents.length;h<_;h++)this._model.data[f.parents[h]].children_d=this._model.data[f.parents[h]].children_d.concat(c);for(c=[],h=0,_=f.children.length;h<_;h++)c[i<=h?h+1:h]=f.children[h];return c[i]=l.id,f.children=c,f.children_d.push(l.id),f.children_d=f.children_d.concat(l.children_d),f.id===E.jstree.root&&(this._model.force_full_redraw=!0),this._model.force_full_redraw||this._node_changed(f.id),a||this.redraw(f.id===E.jstree.root),r&&r.call(this,l,f,i),this.trigger("copy_node",{node:l,original:e,parent:f.id,position:i,old_parent:u,old_position:p&&p._id&&u&&p._model.data[u]&&p._model.data[u].children?E.inArray(e.id,p._model.data[u].children):-1,is_multi:p&&p._id&&p._id!==this._id,is_foreign:!p||!p._id,old_instance:p,new_instance:this}),l.id},cut:function(e){if(e=e||this._data.core.selected.concat(),!(e=!E.vakata.is_array(e)?[e]:e).length)return!1;for(var t=[],i,r,s,r=0,s=e.length;r"),o=e,d=E("
    ",{css:{position:"absolute",top:"-200px",left:t?"0px":"-1000px",visibility:"hidden"}}).appendTo(b.body),c=E("",{value:o,class:"jstree-rename-input",css:{padding:"0",border:"1px solid silver","box-sizing":"border-box",display:"inline-block",height:this._data.core.li_height+"px",lineHeight:this._data.core.li_height+"px",width:"150px"},blur:function(e){e.stopImmediatePropagation(),e.preventDefault();var t,i=n.children(".jstree-rename-input").val(),e=this.settings.core.force_text,e;""===i&&(i=o),d.remove(),n.replaceWith(a),n.remove(),o=e?o:E("
    ").append(E.parseHTML(o)).html(),r=this.get_node(r),this.set_text(r,o),(e=!!this.rename_node(r,e?E("
    ").text(i).text():E("
    ").append(E.parseHTML(i)).html()))||this.set_text(r,o),this._data.core.focused=l.id,setTimeout(function(){var e=this.get_node(l.id,!0);e.length&&(this._data.core.focused=l.id,e.children(".jstree-anchor").trigger("focus"))}.bind(this),0),s&&s.call(this,l,e,h,i),c=null}.bind(this),keydown:function(e){var t=e.which;27===t&&(h=!0,this.value=o),27!==t&&13!==t&&37!==t&&38!==t&&39!==t&&40!==t&&32!==t||e.stopImmediatePropagation(),27!==t&&13!==t||(e.preventDefault(),this.blur())},click:function(e){e.stopImmediatePropagation()},mousedown:function(e){e.stopImmediatePropagation()},keyup:function(e){c.width(Math.min(d.text("pW"+this.value).width(),i))},keypress:function(e){if(13===e.which)return!1}}),t={fontFamily:a.css("fontFamily")||"",fontSize:a.css("fontSize")||"",fontWeight:a.css("fontWeight")||"",fontStyle:a.css("fontStyle")||"",fontStretch:a.css("fontStretch")||"",fontVariant:a.css("fontVariant")||"",letterSpacing:a.css("letterSpacing")||"",wordSpacing:a.css("wordSpacing")||""},n.attr("class",a.attr("class")).append(a.contents().clone()).append(c),a.replaceWith(n),d.css(t),c.css(t).width(Math.min(d.text("pW"+c[0].value).width(),i))[0].select(),void E(b).one("mousedown.jstree touchstart.jstree dnd_start.vakata",function(e){c&&e.target!==c&&E(c).trigger("blur")})):(this.settings.core.error.call(this,this._data.core.last_error),!1))},set_theme:function(e,t){if(!e)return!1;var i,i;(t=!0===t?(i=(i=this.settings.core.themes.dir)||E.jstree.path+"/themes")+"/"+e+"/style.css":t)&&-1===E.inArray(t,r)&&(E("head").append(''),r.push(t)),this._data.core.themes.name&&this.element.removeClass("jstree-"+this._data.core.themes.name),this._data.core.themes.name=e,this.element.addClass("jstree-"+e),this.element[this.settings.core.themes.responsive?"addClass":"removeClass"]("jstree-"+e+"-responsive"),this.trigger("set_theme",{theme:e})},get_theme:function(){return this._data.core.themes.name},set_theme_variant:function(e){this._data.core.themes.variant&&this.element.removeClass("jstree-"+this._data.core.themes.name+"-"+this._data.core.themes.variant),(this._data.core.themes.variant=e)&&this.element.addClass("jstree-"+this._data.core.themes.name+"-"+this._data.core.themes.variant)},get_theme_variant:function(){return this._data.core.themes.variant},show_stripes:function(){this._data.core.themes.stripes=!0,this.get_container_ul().addClass("jstree-striped"),this.trigger("show_stripes")},hide_stripes:function(){this._data.core.themes.stripes=!1,this.get_container_ul().removeClass("jstree-striped"),this.trigger("hide_stripes")},toggle_stripes:function(){this._data.core.themes.stripes?this.hide_stripes():this.show_stripes()},show_dots:function(){this._data.core.themes.dots=!0,this.get_container_ul().removeClass("jstree-no-dots"),this.trigger("show_dots")},hide_dots:function(){this._data.core.themes.dots=!1,this.get_container_ul().addClass("jstree-no-dots"),this.trigger("hide_dots")},toggle_dots:function(){this._data.core.themes.dots?this.hide_dots():this.show_dots()},show_icons:function(){this._data.core.themes.icons=!0,this.get_container_ul().removeClass("jstree-no-icons"),this.trigger("show_icons")},hide_icons:function(){this._data.core.themes.icons=!1,this.get_container_ul().addClass("jstree-no-icons"),this.trigger("hide_icons")},toggle_icons:function(){this._data.core.themes.icons?this.hide_icons():this.show_icons()},show_ellipsis:function(){this._data.core.themes.ellipsis=!0,this.get_container_ul().addClass("jstree-ellipsis"),this.trigger("show_ellipsis")},hide_ellipsis:function(){this._data.core.themes.ellipsis=!1,this.get_container_ul().removeClass("jstree-ellipsis"),this.trigger("hide_ellipsis")},toggle_ellipsis:function(){this._data.core.themes.ellipsis?this.hide_ellipsis():this.show_ellipsis()},set_icon:function(e,t){var i,r,s,a;if(E.vakata.is_array(e)){for(i=0,r=(e=e.slice()).length;i "),r=!1,i+="
  • ",i+="",h.vakata.context.settings.icons&&(i+="'+(t.shortcut_label||"")+"":"")+"",t.submenu&&(s=h.vakata.context._parse(t.submenu,!0))&&(i+=s),i+="
  • ",void(t.separator_after&&(i+="
  •  
  • ",r=!0)))}),i=i.replace(/
  • <\/li\>$/,""),t&&(i+=""),t||(g.html=i,h.vakata.context._trigger("parse")),10"),g.element.on("mouseenter","li",function(e){e.stopImmediatePropagation(),h.contains(this,e.relatedTarget)||(i&&clearTimeout(i),g.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end(),h(this).siblings().find("ul").hide().end().end().parentsUntil(".vakata-context","li").addBack().addClass("vakata-context-hover"),h.vakata.context._show_submenu(this))}).on("mouseleave","li",function(e){h.contains(this,e.relatedTarget)||h(this).find(".vakata-context-hover").addBack().removeClass("vakata-context-hover")}).on("mouseleave",function(e){var t;h(this).find(".vakata-context-hover").removeClass("vakata-context-hover"),h.vakata.context.settings.hide_onmouseleave&&(i=setTimeout((t=this,function(){h.vakata.context.hide()}),h.vakata.context.settings.hide_onmouseleave))}).on("click","a",function(e){e.preventDefault(),h(this).trigger("blur").parent().hasClass("vakata-context-disabled")||!1===h.vakata.context._execute(h(this).attr("rel"))||h.vakata.context.hide()}).on("keydown","a",function(e){var t=null;switch(e.which){case 13:case 32:e.type="click",e.preventDefault(),h(e.currentTarget).trigger(e);break;case 37:g.is_visible&&(g.element.find(".vakata-context-hover").last().closest("li").first().find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover").end().end().children("a").trigger("focus"),e.stopImmediatePropagation(),e.preventDefault());break;case 38:g.is_visible&&((t=!(t=g.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first()).length?g.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").last():t).addClass("vakata-context-hover").children("a").trigger("focus"),e.stopImmediatePropagation(),e.preventDefault());break;case 39:g.is_visible&&(g.element.find(".vakata-context-hover").last().children("ul").show().children("li:not(.vakata-context-separator)").removeClass("vakata-context-hover").first().addClass("vakata-context-hover").children("a").trigger("focus"),e.stopImmediatePropagation(),e.preventDefault());break;case 40:g.is_visible&&((t=!(t=g.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first()).length?g.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").first():t).addClass("vakata-context-hover").children("a").trigger("focus"),e.stopImmediatePropagation(),e.preventDefault());break;case 27:h.vakata.context.hide(),e.preventDefault()}}).on("keydown",function(e){e.preventDefault();var e=g.element.find(".vakata-contextmenu-shortcut-"+e.which).parent();e.parent().not(".vakata-context-disabled")&&e.trigger("click")}),h(b).on("mousedown.vakata.jstree",function(e){g.is_visible&&g.element[0]!==e.target&&!h.contains(g.element[0],e.target)&&h.vakata.context.hide()}).on("context_show.vakata.jstree",function(e,t){g.element.find("li:has(ul)").children("a").addClass("vakata-context-parent"),_&&g.element.addClass("vakata-context-rtl").css("direction","rtl"),g.element.find("ul").hide().end()})}),E.jstree.defaults.dnd={copy:!0,open_timeout:500,is_draggable:!0,check_while_dragging:!0,always_copy:!1,inside_pos:0,drag_selection:!0,touch:!0,large_drop_target:!1,large_drag_target:!1,use_html5:!1,blank_space_drop:!1},E.jstree.plugins.dnd=function(e,o){this.init=function(e,t){o.init.call(this,e,t),this.settings.dnd.use_html5=this.settings.dnd.use_html5&&"draggable"in b.createElement("span")},this.bind=function(){o.bind.call(this),this.element.on(this.settings.dnd.use_html5?"dragstart.jstree":"mousedown.jstree touchstart.jstree",this.settings.dnd.large_drag_target?".jstree-node":".jstree-anchor",function(e){if(this.settings.dnd.large_drag_target&&E(e.target).closest(".jstree-node")[0]!==e.currentTarget)return!0;if("touchstart"===e.type&&(!this.settings.dnd.touch||"selected"===this.settings.dnd.touch&&!E(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").hasClass("jstree-clicked")))return!0;var t=this.get_node(e.target),i=this.is_selected(t)&&this.settings.dnd.drag_selection?this.get_top_selected().length:1,r=1'+r+'+');E.vakata.dnd._trigger("start",e,{helper:E(),element:u,data:d})}}.bind(this)),this.settings.dnd.use_html5&&this.element.on("dragover.jstree",function(e){return e.preventDefault(),E.vakata.dnd._trigger("move",e,{helper:E(),element:u,data:d}),!1}).on("drop.jstree",function(e){return e.preventDefault(),E.vakata.dnd._trigger("stop",e,{helper:E(),element:u,data:d}),!1}.bind(this))},this.redraw_node=function(e,t,i,r){if((e=o.redraw_node.apply(this,arguments))&&this.settings.dnd.use_html5)if(this.settings.dnd.large_drag_target)e.setAttribute("draggable",!0);else{for(var s,a,n=null,s=0,a=e.childNodes.length;s ').hide();E(b).on("dragover.vakata.jstree",function(e){u&&E.vakata.dnd._trigger("move",e,{helper:E(),element:u,data:d})}).on("drop.vakata.jstree",function(e){u&&(E.vakata.dnd._trigger("stop",e,{helper:E(),element:u,data:d}),d=u=null)}).on("dnd_start.vakata.jstree",function(e,t){O=N=!1,t&&t.data&&t.data.jstree&&S.appendTo(b.body)}).on("dnd_move.vakata.jstree",function(e,s){var a=s.event.target!==O.target;if(A&&(s.event&&"dragover"===s.event.type&&!a||clearTimeout(A)),s&&s.data&&s.data.jstree&&(!s.event.target.id||"jstree-marker"!==s.event.target.id)){O=s.event;var n=E.jstree.reference(s.event.target),o=!1,d=!1,t=!1,i,c,l,h,_,g,u,f,p,m,v,j,k,b,y,x,w,C;if(n&&n._data&&n._data.dnd)if(S.attr("class","jstree-"+n.get_theme()+(n.settings.core.themes.responsive?" jstree-dnd-responsive":"")),x=s.data.origin&&(s.data.origin.settings.dnd.always_copy||s.data.origin.settings.dnd.copy&&(s.event.metaKey||s.event.ctrlKey)),s.helper.children().attr("class","jstree-"+n.get_theme()+" jstree-"+n.get_theme()+"-"+n.get_theme_variant()+" "+(n.settings.core.themes.responsive?" jstree-dnd-responsive":"")).find(".jstree-copy").first()[x?"show":"hide"](),s.event.target!==n.element[0]&&s.event.target!==n.get_container_ul()[0]||0!==n.get_container_ul().children().length&&!n.settings.dnd.blank_space_drop){if((o=n.settings.dnd.large_drop_target?E(s.event.target).closest(".jstree-node").children(".jstree-anchor"):E(s.event.target).closest(".jstree-anchor"))&&o.length&&o.parent().is(".jstree-closed, .jstree-open, .jstree-leaf")&&(d=o.offset(),t=(s.event.pageY!==P?s.event:s.event.originalEvent).pageY-d.top,h=o.outerHeight(),u=tE.inArray(s.data.nodes[p],k.children)&&--j),!(f=f&&(n&&n.settings&&n.settings.dnd&&!1===n.settings.dnd.check_while_dragging||n.check(v,s.data.origin&&s.data.origin!==n?s.data.origin.get_node(s.data.nodes[p]):s.data.nodes[p],_,j,{dnd:!0,ref:n.get_node(o.parent()),pos:t,origin:s.data.origin,is_multi:s.data.origin&&s.data.origin!==n,is_foreign:!s.data.origin})))){n&&n.last_error&&(T=n.last_error());break}var i,r;if("i"===t&&o.parent().is(".jstree-closed")&&n.settings.dnd.open_timeout&&(s.event&&"dragover"===s.event.type&&!a||(A&&clearTimeout(A),A=setTimeout((r=o,function(){i.open_node(r)}),(i=n).settings.dnd.open_timeout))),f)return(w=n.get_node(_,!0)).hasClass(".jstree-dnd-parent")||(E(".jstree-dnd-parent").removeClass("jstree-dnd-parent"),w.addClass("jstree-dnd-parent")),N={ins:n,par:_,pos:"i"!==t||"last"!==b||0!==g||n.is_loaded(y)?g:"last"},S.css({left:c+"px",top:l+"px"}).show(),S.removeClass("jstree-above jstree-inside jstree-below").addClass(C),s.helper.find(".jstree-icon").first().removeClass("jstree-er").addClass("jstree-ok"),s.event.originalEvent&&s.event.originalEvent.dataTransfer&&(s.event.originalEvent.dataTransfer.dropEffect=x?"copy":"move"),T={},!(u=!0)}),!0===u))return}else{for(f=!0,p=0,m=s.data.nodes.length;p"),escape:function(e){return f.vakata.html.div.text(e).html()},strip:function(e){return f.vakata.html.div.empty().append(f.parseHTML(e)).text()}}),target:!1,is_down:!1,is_drag:!1,helper:!1,helper_w:0,data:!1,init_x:0,init_y:0,scroll_l:0,scroll_t:0,scroll_e:!1,scroll_i:!1,is_touch:!1},f.vakata.dnd={settings:{scroll_speed:10,scroll_proximity:20,helper_left:5,helper_top:10,threshold:5,threshold_touch:10},_trigger:function(e,t,i){(i=i===P?f.vakata.dnd._get():i).event=t,f(b).triggerHandler("dnd_"+e+".vakata",i)},_get:function(){return{data:p.data,element:p.element,helper:p.helper}},_clean:function(){p.helper&&p.helper.remove(),p.scroll_i&&(clearInterval(p.scroll_i),p.scroll_i=!1),p={element:!1,target:!1,is_down:!1,is_drag:!1,helper:!1,helper_w:0,data:!1,init_x:0,init_y:0,scroll_l:0,scroll_t:0,scroll_e:!1,scroll_i:!1,is_touch:!1},u=null,f(b).off("mousemove.vakata.jstree touchmove.vakata.jstree",f.vakata.dnd.drag),f(b).off("mouseup.vakata.jstree touchend.vakata.jstree",f.vakata.dnd.stop)},_scroll:function(e){if(!p.scroll_e||!p.scroll_l&&!p.scroll_t)return p.scroll_i&&(clearInterval(p.scroll_i),p.scroll_i=!1),!1;if(!p.scroll_i)return p.scroll_i=setInterval(f.vakata.dnd._scroll,100),!1;if(!0===e)return!1;var t=p.scroll_e.scrollTop(),e=p.scroll_e.scrollLeft();p.scroll_e.scrollTop(t+p.scroll_t*f.vakata.dnd.settings.scroll_speed),p.scroll_e.scrollLeft(e+p.scroll_l*f.vakata.dnd.settings.scroll_speed),t===p.scroll_e.scrollTop()&&e===p.scroll_e.scrollLeft()||f.vakata.dnd._trigger("scroll",p.scroll_e)},start:function(e,t,i){"touchstart"===e.type&&e.originalEvent&&e.originalEvent.changedTouches&&e.originalEvent.changedTouches[0]&&(e.pageX=e.originalEvent.changedTouches[0].pageX,e.pageY=e.originalEvent.changedTouches[0].pageY,e.target=b.elementFromPoint(e.originalEvent.changedTouches[0].pageX-window.pageXOffset,e.originalEvent.changedTouches[0].pageY-window.pageYOffset)),p.is_drag&&f.vakata.dnd.stop({});try{e.currentTarget.unselectable="on",e.currentTarget.onselectstart=function(){return!1},e.currentTarget.style&&(e.currentTarget.style.touchAction="none",e.currentTarget.style.msTouchAction="none",e.currentTarget.style.MozUserSelect="none")}catch(e){}return p.init_x=e.pageX,p.init_y=e.pageY,p.data=t,p.is_down=!0,p.element=e.currentTarget,p.target=e.target,p.is_touch="touchstart"===e.type,!1!==i&&(p.helper=f("
    ").html(i).css({display:"block",margin:"0",padding:"0",position:"absolute",top:"-2000px",lineHeight:"16px",zIndex:"10000"})),f(b).on("mousemove.vakata.jstree touchmove.vakata.jstree",f.vakata.dnd.drag),f(b).on("mouseup.vakata.jstree touchend.vakata.jstree",f.vakata.dnd.stop),!1},drag:function(i){if("touchmove"===i.type&&i.originalEvent&&i.originalEvent.changedTouches&&i.originalEvent.changedTouches[0]&&(i.pageX=i.originalEvent.changedTouches[0].pageX,i.pageY=i.originalEvent.changedTouches[0].pageY,i.target=b.elementFromPoint(i.originalEvent.changedTouches[0].pageX-window.pageXOffset,i.originalEvent.changedTouches[0].pageY-window.pageYOffset)),p.is_down){if(!p.is_drag){if(!(Math.abs(i.pageX-p.init_x)>(p.is_touch?f.vakata.dnd.settings.threshold_touch:f.vakata.dnd.settings.threshold)||Math.abs(i.pageY-p.init_y)>(p.is_touch?f.vakata.dnd.settings.threshold_touch:f.vakata.dnd.settings.threshold)))return;p.helper&&(p.helper.appendTo(b.body),p.helper_w=p.helper.outerWidth()),p.is_drag=!0,f(p.target).one("click.vakata",!1),f.vakata.dnd._trigger("start",i)}var e=!1,t=!1,r=!1,s=!1,a=!1,n=!1,o=!1,d=!1,c=!1,l=!1;return p.scroll_t=0,p.scroll_l=0,p.scroll_e=!1,f(f(i.target).parentsUntil("body").addBack().get().reverse()).filter(function(){return this.ownerDocument&&/^auto|scroll$/.test(f(this).css("overflow"))&&(this.scrollHeight>this.offsetHeight||this.scrollWidth>this.offsetWidth)}).each(function(){var e=f(this),t=e.offset();if(this.scrollHeight>this.offsetHeight&&(t.top+e.height()-i.pageYthis.offsetWidth&&(t.left+e.width()-i.pageXa&&(l=a-(p.helper_w+2)),p.helper.css({left:l+"px",top:(c=r&&rs)break;c=_}return{isMatch:0<=a,score:u}},!0===e?{search:t}:t(e)},w.vakata.search.defaults={location:0,distance:100,threshold:.6,fuzzy:!1,caseSensitive:!1},E.jstree.defaults.sort=function(e,t){return this.get_text(e)>this.get_text(t)?1:-1};var m=!(E.jstree.plugins.sort=function(e,t){this.bind=function(){t.bind.call(this),this.element.on("model.jstree",function(e,t){this.sort(t.parent,!0)}.bind(this)).on("rename_node.jstree create_node.jstree",function(e,t){this.sort(t.parent||t.node.parent,!1),this.redraw_node(t.parent||t.node.parent,!0)}.bind(this)).on("move_node.jstree copy_node.jstree",function(e,t){this.sort(t.parent,!1),this.redraw_node(t.parent,!0)}.bind(this))},this.sort=function(e,t){var i,r;if((e=this.get_node(e))&&e.children&&e.children.length&&(e.children.sort(this.settings.sort.bind(this)),t))for(i=0,r=e.children_d.length;ii.ttl)&&(!!(i=(i=i&&i.state?i.state:i)&&E.vakata.is_function(this.settings.state.filter)?this.settings.state.filter.call(this,i):i)&&(this.settings.state.preserve_loaded||delete i.core.loaded,this.element.one("set_state.jstree",function(e,t){t.instance.trigger("restore_state",{state:E.extend(!0,{},i)})}),this.set_state(i),!0))},this.clear_state=function(){return E.vakata.storage.del(this.settings.state.key)}},E.vakata.storage={set:function(e,t){return window.localStorage.setItem(e,t)},get:function(e){return window.localStorage.getItem(e)},del:function(e){return window.localStorage.removeItem(e)}},E.jstree.defaults.types={default:{}},E.jstree.defaults.types[E.jstree.root]={},E.jstree.plugins.types=function(e,l){this.init=function(e,t){var i,r;if(t&&t.types&&t.types.default)for(i in t.types)if("default"!==i&&i!==E.jstree.root&&t.types.hasOwnProperty(i))for(r in t.types.default)t.types.default.hasOwnProperty(r)&&t.types[i][r]===P&&(t.types[i][r]=t.types.default[r]);l.init.call(this,e,t),this._model.data[E.jstree.root].type=E.jstree.root},this.refresh=function(e,t){l.refresh.call(this,e,t),this._model.data[E.jstree.root].type=E.jstree.root},this.bind=function(){this.element.on("model.jstree",function(e,t){for(var i=this._model.data,r=t.nodes,s=this.settings.types,a,n,o="default",d,a=0,n=r.length;a .jstree-ocl",function(e){e.stopImmediatePropagation();var t=E.Event("click",{metaKey:e.metaKey,ctrlKey:e.ctrlKey,altKey:e.altKey,shiftKey:e.shiftKey});E(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(t).trigger("focus")}.bind(this)).on("mouseover.jstree",".jstree-wholerow, .jstree-icon",function(e){return e.stopImmediatePropagation(),this.is_disabled(e.currentTarget)||this.hover_node(e.currentTarget),!1}.bind(this)).on("mouseleave.jstree",".jstree-node",function(e){this.dehover_node(e.currentTarget)}.bind(this))},this.teardown=function(){this.settings.wholerow&&this.element.find(".jstree-wholerow").remove(),a.teardown.call(this)},this.redraw_node=function(e,t,i,r){var s;return(e=a.redraw_node.apply(this,arguments))&&(s=j.cloneNode(!0),-1!==E.inArray(e.id,this._data.core.selected)&&(s.className+=" jstree-wholerow-clicked"),this._data.core.focused&&this._data.core.focused===e.id&&(s.className+=" jstree-wholerow-hovered"),e.insertBefore(s,e.childNodes[0])),e}},window.customElements&&Object&&Object.create){var e=Object.create(HTMLElement.prototype);e.createdCallback=function(){var e={core:{},plugins:[]},t;for(t in E.jstree.plugins)E.jstree.plugins.hasOwnProperty(t)&&this.attributes[t]&&(e.plugins.push(t),this.getAttribute(t)&&JSON.parse(this.getAttribute(t))&&(e[t]=JSON.parse(this.getAttribute(t))));for(t in E.jstree.defaults.core)E.jstree.defaults.core.hasOwnProperty(t)&&this.attributes[t]&&(e.core[t]=JSON.parse(this.getAttribute(t))||this.getAttribute(t));E(this).jstree(e)};try{window.customElements.define("vakata-jstree",function(){},{prototype:e})}catch(e){}}}}); diff --git a/orochi/static/js/jstree/jstreetable.js b/orochi/static/js/jstree/jstreetable.js deleted file mode 100644 index 8fe1fa6b..00000000 --- a/orochi/static/js/jstree/jstreetable.js +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * http://github.com/adamjimenez/jstree-table - * - * This plugin handles adding columns to a tree to display additional data - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Works only with jstree version >= 3.0.0 - * - * $Revision: 3.4.2 $ - */ - -/*jslint nomen:true */ -/*jshint unused:vars */ -/*global navigator, document, jQuery, define, localStorage */ - -(function (factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['jquery', 'jstree'], factory); - } else { - // Browser globals - factory(jQuery); - } -}(function ($) { - var renderATitle, getIndent, copyData, htmlstripre, findLastClosedNode, BLANKRE = /^\s*$/g, - IDREGEX = /[\\:&!^|()\[\]<>@*'+~#";,= \/${}%]/g, escapeId = function (id) { - return (id||"").replace(IDREGEX,'\\$&'); - }, NODE_DATA_ATTR = "data-jstreetable", COL_DATA_ATTR = "data-jstreetable-column", - SPECIAL_TITLE = "_DATA_", LEVELINDENT = 24, styled = false, TABLECELLID_PREFIX = "jstable_",TABLECELLID_POSTFIX = "_col", - MINCOLWIDTH = 10, - findDataCell = function (from,id) { - return from.find("div["+NODE_DATA_ATTR+'="'+ escapeId(id) +'"]'); - }, - isClickedSep = false, toResize = null, oldMouseX = 0, newMouseX = 0; - - /*jslint regexp:true */ - htmlstripre = /<\/?[^>]+>/gi; - /*jslint regexp:false */ - - getIndent = function(node,tree) { - var div, i, li, width; - - // did we already save it for this tree? - tree._tableSettings = tree._tableSettings || {}; - if (tree._tableSettings.indent > 0) { - width = tree._tableSettings.indent; - } else { - // create a new div on the DOM but not visible on the page - div = $("
    "); - i = node.prev("i"); - li = i.parent(); - // add to that div all of the classes on the tree root - div.addClass(tree.get_node("#",true).attr("class")); - - // move the li to the temporary div root - li.appendTo(div); - - // attach to the body quickly - div.appendTo($("body")); - - // get the width - width = i.width() || LEVELINDENT; - - // detach the li from the new div and destroy the new div - li.detach(); - div.remove(); - - // save it for the future - tree._tableSettings.indent = width; - } - - - return(width); - - }; - - copyData = function (fromtree,from,totree,to,recurse) { - var i, j; - to.data = $.extend(true, {}, from.data); - if (from && from.children_d && recurse) { - for(i = 0, j = from.children_d.length; i < j; i++) { - copyData(fromtree,fromtree.get_node(from.children_d[i]),totree,totree.get_node(to.children_d[i]),recurse); - } - } - }; - - findLastClosedNode = function (tree,id) { - // first get our node - var ret, node = tree.get_node(id), children = node.children; - // is it closed? - if (!children || children.length <= 0 || !node.state.opened) { - ret = id; - } else { - ret = findLastClosedNode(tree,children[children.length-1]); - } - return(ret); - }; - - renderAWidth = function(node,tree) { - var depth, width, - fullWidth = parseInt(tree.settings.table.columns[0].width,10) + parseInt(tree._tableSettings.treeWidthDiff,10); - // need to use a selector in jquery 1.4.4+ - depth = tree.get_node(node).parents.length; - width = fullWidth - depth*getIndent(node,tree); - // the following line is no longer needed, since we are doing this inside a - //a.css({"vertical-align": "top", "overflow":"hidden"}); - return(fullWidth); - }; - renderATitle = function(node,t,tree) { - var a = node.get(0).tagName.toLowerCase() === "a" ? node : node.children("a"), title, col = tree.settings.table.columns[0]; - // get the title - title = ""; - if (col.title) { - if (col.title === SPECIAL_TITLE) { - title = tree.get_text(t); - } else if (t.attr(col.title)) { - title = t.attr(col.title); - } - } - // strip out HTML - title = title.replace(htmlstripre, ''); - if (title) { - a.attr("title",title); - } - }; - - $.jstree.defaults.table = { - width: 'auto' - }; - - $.jstree.plugins.table = function(options,parent) { - var _this = this; - - this._initialize = function () { - if (!this._initialized) { - var s = this.settings.table || {}, styles, container = this.element, i, - gs = this._tableSettings = { - columns : s.columns || [], - treeClass : "jstree-table-col-0", - context: s.contextmenu || false, - columnWidth : s.columnWidth, - defaultConf : {"*display":"inline","*+display":"inline"}, - isThemeroller : !!this._data.themeroller, - treeWidthDiff : 0, - resizable : s.resizable, - draggable : s.draggable, - stateful: s.stateful, - indent: 0, - sortFn: [], - sortOrder: 'text', - sortAsc: true, - fixedHeader: s.fixedHeader !== false, - headerContextMenu: s.headerContextMenu !== false, - checkIcon: 'fa fa-check', - arrowDownIcon: 'fa fa-chevron-down', - arrowUpIcon: 'fa fa-chevron-up', - width: s.width, - height: s.height - }, cols = gs.columns, treecol = 0; - // find which column our tree shuld go in - for (i=0;i'+styles.join("\n")+'').appendTo("head"); - } - this.tableWrapper = $("
    ").addClass("jstree-table-wrapper").insertAfter(container); - this.headerWrapper = $("
    ").addClass("jstree-table-headerwrapper").appendTo(this.tableWrapper); - this.midWrapper = $("
    ").addClass("jstree-table-midwrapper").appendTo(this.tableWrapper); - // set the wrapper width - if (s.width) { - this.tableWrapper.width(s.width); - } - if (s.height) { - this.tableWrapper.height(s.height); - } - // create the data columns - for (i=0;i").addClass("jstree-default jstree-table-column jstree-table-column-"+i+" jstree-table-column-root-"+this.rootid).appendTo(this.midWrapper); - } - this.midWrapper.children("div:eq("+treecol+")").append(container); - container.addClass("jstree-table-cell"); - - //move header with scroll - /* - if (gs.fixedHeader) { - this.tableWrapper.scroll(function() { - $(this).find('.jstree-table-header').css('top', $(this).scrollTop()); - }); - } - */ - - // copy original sort function - var defaultSort = $.proxy(this.settings.sort, this); - - // override sort function - this.settings.sort = function (a, b) { - var bigger; - - if (gs.sortOrder==='text') { - bigger = defaultSort(a, b); - } else { - var nodeA = this.get_node(a); - var nodeB = this.get_node(b); - var valueA = nodeA.data[gs.sortOrder]; - var valueB = nodeB.data[gs.sortOrder]; - if(valueA && valueB){ - if(gs.sortFn[gs.sortOrder]){ - bigger = gs.sortFn[gs.sortOrder](valueA, valueB, nodeA, nodeB); - }else{ - // Default sorting - bigger = (valueA > valueB ? 1 : -1); - } - }else{ - // undefined is second - if(valueA){ - bigger = 1; - }else if(valueB){ - bigger = -1; - }else{ - // Compare two nodes without values - bigger = defaultSort(a, b); - } - } - } - - if (gs.sortAsc===false){ - bigger = -bigger; - - } - - return bigger; - }; - - // sortable columns when jQuery UI is available - if (gs.draggable) { - if (!$.ui || !$.ui.sortable) { - console.warn('[jstree-table] draggable option requires jQuery UI'); - } else { - var from, to; - this.headerWrapper.sortable({ - axis: "x", - //handle: ".jstree-table-header-cell", - cancel: ".jstree-table-separator", - start: function (event, ui) { - ui.item.parent().children().css('display', 'inline-block'); - from = ui.item.index(); - }, - stop: function (event, ui) { - ui.item.parent().children().css('display', 'table-cell'); - to = ui.item.index(); - - if (to===from) return; - - gs.columns.splice(to, 0, gs.columns.splice(from, 1)[0]); - - var col = $('.jstree-table-midwrapper>div').eq(from); - if (to>from) { - col.insertAfter(col.parent().children("div").eq(to)); - } else if (to\ - div.jstree-table-cell-root-'+me.rootid+' {line-height: '+anchorHeight+'px; min-height: '+anchorHeight+'px;}\ - div.jstree-table-midwrapper a.jstree-clicked:before, .jstree-table-midwrapper a.jstree-hovered:before {width: ' + tableWidth + 'px;}\ - ').appendTo("head"); - } - - resize(); - - // resize column headers - this.autosize_all_columns(); - - // resize rows on zoom - $(window).on('resize', resize); - - // resize column expand - this.element.on("resize_column.jstree-table", resize); - },this)) - .on("move_node.jstree",$.proxy(function(e,data) { - var node = data.new_instance.element; - //renderAWidth(node,this); - // check all the children, because we could drag a tree over - node.find("li > a").each($.proxy(function(i,elm) { - //renderAWidth($(elm),this); - },this)); - },this)) - .on("select_node.jstree",$.proxy(function(node,selected,event){ - var id = selected.node.id; - findDataCell(this.tableWrapper,id).addClass("jstree-clicked"); - this.get_node(selected.node.id,true).children("div.jstree-table-cell").addClass("jstree-clicked"); - },this)) - .on("deselect_node.jstree",$.proxy(function(node,selected,event){ - var id = selected.node.id; - findDataCell(this.tableWrapper,id).removeClass("jstree-clicked"); - },this)) - .on("deselect_all.jstree",$.proxy(function(node,selected,event){ - // get all of the ids that were unselected - var ids = selected.node || [], i; - for (i=0;i"); - //col.appendTo(colgroup); - cl = cols[i].headerClass || ""; - ccl = cols[i].columnClass || ""; - val = cols[i].header || ""; - name = cols[i].value || "text"; - - if (val) {hasHeaders = true;} - if(gs.stateful && localStorage['jstree-root-'+rootid+'-column-'+i]) - width = localStorage['jstree-root-'+rootid+'-column-'+i]; - else - width = cols[i].width || defaultWidth; - - col = this.headerWrapper; - last = $("
    ").css(conf).addClass("jstree-table-div-"+this.uniq+"-"+i+" "+(tr?"ui-widget-header ":"")+" jstree-table-header jstree-table-header-cell jstree-table-header-"+classAdd+" "+cl+" "+ccl).html(val); - last.addClass((tr?"ui-widget-header ":"")+"jstree-table-header jstree-table-header-"+classAdd); - last.appendTo(col); - - if (name) { - last.attr(COL_DATA_ATTR, name); - } - last.hover(function () { - $(this).addClass("jstree-hovered jstree-table-header-hovered"); - }, function () { - $(this).removeClass("jstree-hovered jstree-table-header-hovered"); - }); - totalWidth += last.outerWidth(); - puller = $("
     
    ").appendTo(last); - } - - last.addClass((tr?"ui-widget-header ":"")+"jstree-table-header jstree-table-header-last jstree-table-header-"+classAdd); - // if there is no width given for the last column, do it via automatic - if (cols[cols.length-1].width === undefined) { - totalWidth -= width; - col.css({width:"auto"}); - last.addClass("jstree-table-width-auto").next(".jstree-table-separator").remove(); - } - if (hasHeaders) { - // save the offset of the div from the body - //gs.divOffset = header.parent().offset().left; - gs.header = header; - } else { - $("div.jstree-table-header").hide(); - } - - if (!this.bound && resizable) { - this.bound = true; - $(document).mouseup(function () { - var ref, cols, width, headers, currentTree, colNum; - if (isClickedSep) { - colNum = toResize.prevAll(".jstree-table-column").length; - currentTree = toResize.closest(".jstree-table-wrapper").find(".jstree"); - ref = $.jstree.reference(currentTree); - cols = ref.settings.table.columns; - headers = toResize.parent().children("div.jstree-table-column"); - if (isNaN(colNum) || colNum < 0) { ref._tableSettings.treeWidthDiff = currentTree.find("ins:eq(0)").width() + currentTree.find("a:eq(0)").width() - ref._tableSettings.columns[0].width; } - width = ref._tableSettings.columns[colNum].width = parseFloat(toResize.css("width")); - isClickedSep = false; - toResize = null; - - currentTree.trigger("resize_column.jstree-table", [colNum,width]); - } - }).mousemove(function (e) { - if (isClickedSep) { - newMouseX = e.pageX; - var diff = newMouseX - oldMouseX, - oldPrevHeaderInner, - oldPrevColWidth, newPrevColWidth; - - if (diff !== 0) { - oldPrevHeaderInner = toResize.width(); - oldPrevColWidth = parseFloat(toResize.css("width")); - - // handle a Chrome issue with columns set to auto - // thanks to Brabus https://github.com/side-by-side - if (!oldPrevColWidth) { - oldPrevColWidth = toResize.innerWidth(); - } - - // make sure that diff cannot be beyond the left/right limits - diff = diff < 0 ? Math.max(diff,-oldPrevHeaderInner) : diff; - newPrevColWidth = oldPrevColWidth+diff; - - // only do this if we are not shrinking past 0 on left - and limit it to that amount - if ((diff > 0 || oldPrevHeaderInner > 0) && newPrevColWidth > MINCOLWIDTH) { - var index = toResize.parent().children().index(toResize); - var col = $('.jstree-table-midwrapper>div').eq(index); - - toResize.width(newPrevColWidth+"px"); - toResize.css("min-width",newPrevColWidth+"px"); - toResize.css("max-width",newPrevColWidth+"px"); - - col.width(newPrevColWidth+"px"); - col.css("min-width",newPrevColWidth+"px"); - col.css("max-width",newPrevColWidth+"px"); - - oldMouseX = newMouseX; - } - } - } - }); - this.tableWrapper.on("selectstart", ".jstree-table-resizable-separator", function () { - return false; - }) - .on("mousedown", ".jstree-table-resizable-separator", function (e) { - isClickedSep = true; - oldMouseX = e.pageX; - toResize = $(this).closest("div.jstree-table-header"); - // the max rightmost position we will allow is the right-most of the wrapper minus a buffer (10) - return false; - }) - .on("dblclick", ".jstree-table-resizable-separator", function (e) { - var headerCol = $(this).closest("div.jstree-table-header"); - var index = headerCol.parent().children().index(headerCol); - var col = $('.jstree-table-midwrapper>div').eq(index); - _this.autosize_column(col); - }) - .on("click", ".jstree-table-separator", function (e) { - // don't sort after resize - e.stopPropagation(); - }); - } - - this.tableWrapper.on("click", ".jstree-table-header-cell", function (e) { - if (!_this.sort) { return; } - - // get column - var name = $(this).attr(COL_DATA_ATTR); - if (!name) { return; } - - // sort order - var arrowClass; - if (gs.sortOrder === name && gs.sortAsc === true) { - gs.sortAsc = false; - arrowClass = gs.arrowDownIcon; - } else { - gs.sortOrder = name; - gs.sortAsc = true; - arrowClass = gs.arrowUpIcon; - } - - // add sort arrow - $(this).closest('.jstree-table-wrapper').find(".jstree-table-sort-icon").remove(); - $("").addClass("jstree-table-sort-icon").appendTo($(this)).addClass(arrowClass); - - // sort by column - var rootNode = _this.get_node('#'); - _this.sort(rootNode, true); - _this.redraw_node(rootNode, true); - }); - - // header context menu - this.headerWrapper.on("contextmenu", ".jstree-table-header-cell", function(e) { - if (!gs.headerContextMenu) { return; } - e.preventDefault(); - - var options = { - "fit":{label:"Size column to fit","action": function (data) { - var headerCol = $(e.target).closest("div.jstree-table-header"); - var index = headerCol.parent().children().index(headerCol); - var col = $('.jstree-table-midwrapper>div').eq(index); - - _this.autosize_column(col); - }}, - "fitAll":{"separator_after": true,label:"Size all columns to fit","action": function (data) { - _this.autosize_all_columns(); - }} - }; - - // create menu item for every header cell - var cell, icon, value, label; - _this.midWrapper.find(".jstree-table-header-cell").each(function() { - cell = $(this); - icon = cell.is(":visible") ? gs.checkIcon : false; - value = cell.attr(COL_DATA_ATTR); - //get label without sorting arrows - label = cell.clone().children('.jstree-table-sort-icon').remove().end().text().trim(); - - options[value] = {icon:icon, column:value, label:label, _disabled: (value === 'text'), "action": function (data) { - var col = _this.midWrapper.find(".jstree-table-header-cell["+COL_DATA_ATTR+"='"+data.item.column+"']").parent(); - col.toggle(); - }}; - }); - - $.vakata.context.show(this,{ 'x' : e.pageX, 'y' : e.pageY },options); - }); - }; - - - /* - * Override redraw_node to correctly insert the table - */ - this.redraw_node = function(obj, deep, is_callback, force_render) { - // first allow the parent to redraw the node - obj = parent.redraw_node.call(this, obj, deep, is_callback, force_render); - // next prepare the table - if(obj) { - this._prepare_table(obj); - } - return obj; - }; - this.refresh = function () { - this._clean_table(); - return parent.refresh.apply(this,arguments); - }; - /* - * Override set_id to update cell attributes - */ - this.set_id = function (obj, id) { - var old; - if(obj) { - old = obj.id; - } - var result = parent.set_id.apply(this,arguments); - if(result) { - if (old !== undefined) { - var table = this.tableWrapper, oldNodes = [old], i; - // get children - if (obj && obj.children_d) { - oldNodes = oldNodes.concat(obj.children_d); - } - // update id in children - for (i=0;i", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"), - h2 = $("<"+"input />", { - "value" : t, - "class" : "jstree-rename-input", - "css" : { - "padding" : "0", - "border" : "1px solid silver", - "box-sizing" : "border-box", - "display" : "inline-block", - "height" : (this._data.core.li_height) + "px", - "lineHeight" : (this._data.core.li_height) + "px", - "width" : "150px" // will be set a bit further down - }, - "blur" : $.proxy(function () { - var v = h2.val(); - // save the value if changed - if(v === "" || v === t) { - v = t; - } else { - obj.data[col.value] = v; - this.element.trigger('update_cell.jstree-table',{node:obj, col:col.value, value:v, old:t}); - this._prepare_table(this.get_node(obj,true)); - } - h2.remove(); - element.show(); - }, this), - "keydown" : function (event) { - var key = event.which; - if(key === 27) { - this.value = t; - } - if(key === 27 || key === 13 || key === 37 || key === 38 || key === 39 || key === 40 || key === 32) { - event.stopImmediatePropagation(); - } - if(key === 27 || key === 13) { - event.preventDefault(); - this.blur(); - } - }, - "click" : function (e) { e.stopImmediatePropagation(); }, - "mousedown" : function (e) { e.stopImmediatePropagation(); }, - "keyup" : function (event) { - h2.width(Math.min(h1.text("pW" + this.value).width(),w)); - }, - "keypress" : function(event) { - if(event.which === 13) { return false; } - } - }), - fn = { - fontFamily : element.css('fontFamily') || '', - fontSize : element.css('fontSize') || '', - fontWeight : element.css('fontWeight') || '', - fontStyle : element.css('fontStyle') || '', - fontStretch : element.css('fontStretch') || '', - fontVariant : element.css('fontVariant') || '', - letterSpacing : element.css('letterSpacing') || '', - wordSpacing : element.css('wordSpacing') || '' - }; - element.hide(); - element.parent().append(h2); - h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select(); - }; - - this.autosize_column = function (col) { - // don't resize hidden columns - if (col.is(":hidden")) { return; } - - var oldPrevColWidth = parseFloat(col.css("width")), newWidth = 0, diff, - colNum = col.prevAll(".jstree-table-column").length, - oldPrevHeaderInner = col.width(), newPrevColWidth; - - //find largest width - col.find(".jstree-table-cell").each(function() { - var item = $(this), width; - item.css("position", "absolute"); - item.css("width", "auto"); - width = item.outerWidth(); - item.css("position", "static"); - - if (width>newWidth) { - newWidth = width; - } - }); - - diff = newWidth-oldPrevColWidth; - - // make sure that diff cannot be beyond the left limits - diff = diff < 0 ? Math.max(diff,-oldPrevHeaderInner) : diff; - newPrevColWidth = (oldPrevColWidth+diff)+"px"; - - col.width(newPrevColWidth); - col.css("min-width",newPrevColWidth); - col.css("max-width",newPrevColWidth); - - var index = col.parent().children().index(col); - var headerCol = $('.jstree-table-headerwrapper>div').eq(index); - headerCol.width(newPrevColWidth); - headerCol.css("min-width",newPrevColWidth); - headerCol.css("max-width",newPrevColWidth); - - $(this).closest(".jstree-table-wrapper").find(".jstree").trigger("resize_column.jstree-table",[colNum,newPrevColWidth]); - }; - - this.autosize_all_columns = function () { - this.tableWrapper.find(".jstree-table-column").each(function() { - _this.autosize_column($(this)); - }); - }; - - this._prepare_table = function (obj) { - var gs = this._tableSettings, c = gs.treeClass, _this = this, t, cols = gs.columns || [], width, tr = gs.isThemeroller, - tree = this.element, rootid = this.rootid, - classAdd = (tr?"themeroller":"regular"), img, objData = this.get_node(obj), - defaultWidth = gs.columnWidth, conf = gs.defaultConf, cellClickHandler = function (tree,node,val,col,t) { - return function(e) { - node.children(".jstree-anchor").trigger("click",e); - }; - }, cellDblClickHandler = function (tree,node,val,col,t) { - return function(e) { - node.children(".jstree-anchor").trigger("dblclick",e); - }; - }, cellRightClickHandler = function (tree,node,val,col,t) { - return function (e) { - if (gs.context) { - e.preventDefault(); - $.vakata.context.show(this,{ 'x' : e.pageX, 'y' : e.pageY },{ - "edit":{label:"Edit","action": function (data) { - var obj = t.get_node(node); - _this._edit(obj,col,e.target); - }} - }); - } - }; - }, - hoverInHandler = function (node, jsTreeInstance) { - return function() { jsTreeInstance.hover_node(node); }; - }, - hoverOutHandler = function (node, jsTreeInstance) { - return function() { jsTreeInstance.dehover_node(node); }; - }, - i, val, cl, wcl, ccl, a, last, valClass, wideValClass, span, paddingleft, title, tableCellName, tableCellParentId, tableCellParent, - tableCellPrev, tableCellPrevId, tableCellNext, tableCellNextId, tableCellChild, tableCellChildId, - col, content, tmpWidth, mw = this.midWrapper, dataCell, lid = objData.id, - peers = this.get_node(objData.parent).children, - // find my position in the list of peers. "peers" is the list of everyone at my level under my parent, in order - pos = $.inArray(lid,peers), - hc = this.holdingCells, rendered = false, closed; - // get our column definition - t = $(obj); - - // find the a children - a = t.children("a"); - - if (a.length === 1) { - closed = !objData.state.opened; - tableCellName = TABLECELLID_PREFIX+escapeId(lid)+TABLECELLID_POSTFIX; - tableCellParentId = objData.parent === "#" ? null : objData.parent; - a.addClass(c); - //renderAWidth(a,_this); - renderATitle(a,t,_this); - last = a; - // find which column our tree shuld go in - var s = this.settings.table; - var treecol = 0; - for (i=0;i' : '';} - } else { content = val; } - - // content cannot be blank, or it messes up heights - if (content === undefined || content === null || BLANKRE.test(content)) { - content = " "; - } - - // get the valueClass - valClass = col.valueClass && objData.data !== null && objData.data !== undefined ? objData.data[col.valueClass] || "" : ""; - if (valClass && col.valueClassPrefix && col.valueClassPrefix !== "") { - valClass = col.valueClassPrefix + valClass; - } - // get the wideValueClass - wideValClass = col.wideValueClass && objData.data !== null && objData.data !== undefined ? objData.data[col.wideValueClass] || "" : ""; - if (wideValClass && col.wideValueClassPrefix && col.wideValueClassPrefix !== "") { - wideValClass = col.wideValueClassPrefix + wideValClass; - } - // get the title - title = col.title && objData.data !== null && objData.data !== undefined ? objData.data[col.title] || "" : ""; - // strip out HTML - if (typeof title === 'string') { - title = title.replace(htmlstripre, ''); - } - - // get the width - paddingleft = 7; - width = col.width || defaultWidth; - if (width !== 'auto') { - width = tmpWidth || (width - paddingleft); - } - - last = findDataCell(dataCell, lid); - if (!last || last.length < 1) { - last = $("
    "); - $("").appendTo(last); - last.attr("id",tableCellName+i); - last.addClass(tableCellName); - last.attr(NODE_DATA_ATTR,lid); - - } - // we need to put it in the dataCell - after the parent, but the position matters - // if we have no parent, then we are one of the root nodes, but still need to look at peers - - - // if we are first, i.e. pos === 0, we go right after the parent; - // if we are not first, and our previous peer (one before us) is closed, we go right after the previous peer cell - // if we are not first, and our previous peer is opened, then we have to find its youngest & lowest closed child (incl. leaf) - // - // probably be much easier to go *before* our next one - // but that one might not be drawn yet - // here is the logic for jstree drawing: - // it draws peers from first to last or from last to first - // it draws children before a parent - // - // so I can rely on my *parent* not being drawn, but I cannot rely on my previous peer or my next peer being drawn - - // so we do the following: - // 1- We are the first child: install after the parent - // 2- Our previous peer is already drawn: install after the previous peer - // 3- Our previous peer is not drawn, we have a child that is drawn: install right before our first child - // 4- Our previous peer is not drawn, we have no child that is drawn, our next peer is drawn: install right before our next peer - // 5- Our previous peer is not drawn, we have no child that is drawn, our next peer is not drawn: install right after parent - tableCellPrevId = pos <=0 ? objData.parent : findLastClosedNode(this,peers[pos-1]); - tableCellPrev = findDataCell(dataCell,tableCellPrevId); - tableCellNextId = pos >= peers.length-1 ? "NULL" : peers[pos+1]; - tableCellNext = findDataCell(dataCell,tableCellNextId); - tableCellChildId = objData.children && objData.children.length > 0 ? objData.children[0] : "NULL"; - tableCellChild = findDataCell(dataCell,tableCellChildId); - tableCellParent = findDataCell(dataCell,tableCellParentId); - - // if our parent is already drawn, then we put this in the right order under our parent - if (tableCellParentId) { - if (tableCellParent && tableCellParent.length > 0) { - if (tableCellPrev && tableCellPrev.length > 0) { - last.insertAfter(tableCellPrev); - } else if (tableCellChild && tableCellChild.length > 0) { - last.insertBefore(tableCellChild); - } else if (tableCellNext && tableCellNext.length > 0) { - last.insertBefore(tableCellNext); - } else { - last.insertAfter(tableCellParent); - } - rendered = true; - } else { - rendered = false; - } - // always put it in the holding cells, and then sort when the parent comes in, in case parent is (re)drawn later - hc[tableCellName+i] = last; - } else { - if (tableCellPrev && tableCellPrev.length > 0) { - last.insertAfter(tableCellPrev); - } else if (tableCellChild && tableCellChild.length > 0) { - last.insertBefore(tableCellChild); - } else if (tableCellNext && tableCellNext.length > 0) { - last.insertBefore(tableCellNext); - } else { - last.appendTo(dataCell); - } - rendered = true; - } - // do we have any children waiting for this cell? walk down through the children/grandchildren/etc tree - if (rendered) { - last.after(this.getHoldingCells(objData,i,hc)); - } - // need to make the height of this match the line height of the tree. How? - span = last.children("span"); - - // create a span inside the div, so we can control what happens in the whole div versus inside just the text/background - span.addClass(cl+" "+valClass).html(content); - last = last.css(conf).addClass("jstree-table-cell jstree-table-cell-regular jstree-table-cell-root-"+rootid+" jstree-table-cell-"+classAdd+" "+wcl+ " " + wideValClass + (tr?" ui-state-default":"")).addClass("jstree-table-col-"+i); - // add click handler for clicking inside a table cell - last.click(cellClickHandler(tree,t,val,col,this)); - last.dblclick(cellDblClickHandler(tree,t,val,col,this)); - last.on("contextmenu",cellRightClickHandler(tree,t,val,col,this)); - last.hover(hoverInHandler(t, this), hoverOutHandler(t, this)); - - if (title) { - span.attr("title",title); - } - } - last.addClass("jstree-table-cell-last"+(tr?" ui-state-default":"")); - // if there is no width given for the last column, do it via automatic - if (cols[cols.length-1].width === undefined) { - last.addClass("jstree-table-width-auto").next(".jstree-table-separator").remove(); - } - } - this.element.css({'overflow-y':'auto !important'}); - }; - // clean up holding cells - this.holdingCells = {}; - }; -})); diff --git a/orochi/static/js/wunderbaum/wunderbaum.umd.js b/orochi/static/js/wunderbaum/wunderbaum.umd.js new file mode 100644 index 00000000..7475d319 --- /dev/null +++ b/orochi/static/js/wunderbaum/wunderbaum.umd.js @@ -0,0 +1,7881 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.mar10 = {})); +})(this, (function (exports) { 'use strict'; + + /*! + * debounce & throttle, taken from https://github.com/lodash/lodash v4.17.21 + * MIT License: https://raw.githubusercontent.com/lodash/lodash/4.17.21-npm/LICENSE + * Modified for TypeScript type annotations. + */ + /* --- */ + /** Detect free variable `global` from Node.js. */ + const freeGlobal = typeof global === "object" && + global !== null && + global.Object === Object && + global; + /** Detect free variable `globalThis` */ + const freeGlobalThis = typeof globalThis === "object" && + globalThis !== null && + globalThis.Object == Object && + globalThis; + /** Detect free variable `self`. */ + const freeSelf = typeof self === "object" && self !== null && self.Object === Object && self; + /** Used as a reference to the global object. */ + const root = freeGlobalThis || freeGlobal || freeSelf || Function("return this")(); + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * isObject({}) + * // => true + * + * isObject([1, 2, 3]) + * // => true + * + * isObject(Function) + * // => true + * + * isObject(null) + * // => false + */ + function isObject(value) { + const type = typeof value; + return value != null && (type === "object" || type === "function"); + } + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked, or until the next browser frame is drawn. The debounced function + * comes with a `cancel` method to cancel delayed `func` invocations and a + * `flush` method to immediately invoke them. Provide `options` to indicate + * whether `func` should be invoked on the leading and/or trailing edge of the + * `wait` timeout. The `func` is invoked with the last arguments provided to the + * debounced function. Subsequent calls to the debounced function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until the next tick, similar to `setTimeout` with a timeout of `0`. + * + * If `wait` is omitted in an environment with `requestAnimationFrame`, `func` + * invocation will be deferred until the next frame is drawn (typically about + * 16ms). + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `debounce` and `throttle`. + * + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] + * The number of milliseconds to delay; if omitted, `requestAnimationFrame` is + * used (if available). + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', debounce(calculateLayout, 150)) + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })) + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * const debounced = debounce(batchLog, 250, { 'maxWait': 1000 }) + * const source = new EventSource('/stream') + * jQuery(source).on('message', debounced) + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel) + * + * // Check for pending invocations. + * const status = debounced.pending() ? "Pending..." : "Ready" + */ + function debounce(func, wait = 0, options = {}) { + let lastArgs, lastThis, maxWait, result, timerId, lastCallTime; + let lastInvokeTime = 0; + let leading = false; + let maxing = false; + let trailing = true; + // Bypass `requestAnimationFrame` by explicitly setting `wait=0`. + const useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === "function"; + if (typeof func !== "function") { + throw new TypeError("Expected a function"); + } + wait = +wait || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = "maxWait" in options; + maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait; + trailing = "trailing" in options ? !!options.trailing : trailing; + } + function invokeFunc(time) { + const args = lastArgs; + const thisArg = lastThis; + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + function startTimer(pendingFunc, wait) { + if (useRAF) { + root.cancelAnimationFrame(timerId); + return root.requestAnimationFrame(pendingFunc); + } + return setTimeout(pendingFunc, wait); + } + function cancelTimer(id) { + if (useRAF) { + return root.cancelAnimationFrame(id); + } + clearTimeout(id); + } + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = startTimer(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + function remainingWait(time) { + const timeSinceLastCall = time - lastCallTime; + const timeSinceLastInvoke = time - lastInvokeTime; + const timeWaiting = wait - timeSinceLastCall; + return maxing + ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } + function shouldInvoke(time) { + const timeSinceLastCall = time - lastCallTime; + const timeSinceLastInvoke = time - lastInvokeTime; + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || + timeSinceLastCall >= wait || + timeSinceLastCall < 0 || + (maxing && timeSinceLastInvoke >= maxWait)); + } + function timerExpired() { + const time = Date.now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = startTimer(timerExpired, remainingWait(time)); + } + function trailingEdge(time) { + timerId = undefined; + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + function cancel() { + if (timerId !== undefined) { + cancelTimer(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + function flush() { + return timerId === undefined ? result : trailingEdge(Date.now()); + } + function pending() { + return timerId !== undefined; + } + function debounced(...args) { + const time = Date.now(); + const isInvoking = shouldInvoke(time); + lastArgs = args; + // eslint-disable-next-line @typescript-eslint/no-this-alias + lastThis = this; + lastCallTime = time; + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = startTimer(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = startTimer(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + debounced.pending = pending; + return debounced; + } + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds (or once per browser frame). The throttled function + * comes with a `cancel` method to cancel delayed `func` invocations and a + * `flush` method to immediately invoke them. Provide `options` to indicate + * whether `func` should be invoked on the leading and/or trailing edge of the + * `wait` timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until the next tick, similar to `setTimeout` with a timeout of `0`. + * + * If `wait` is omitted in an environment with `requestAnimationFrame`, `func` + * invocation will be deferred until the next frame is drawn (typically about + * 16ms). + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `throttle` and `debounce`. + * + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] + * The number of milliseconds to throttle invocations to; if omitted, + * `requestAnimationFrame` is used (if available). + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', throttle(updatePosition, 100)) + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * const throttled = throttle(renewToken, 300000, { 'trailing': false }) + * jQuery(element).on('click', throttled) + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel) + */ + function throttle(func, wait = 0, options = {}) { + let leading = true; + let trailing = true; + if (typeof func !== "function") { + throw new TypeError("Expected a function"); + } + if (isObject(options)) { + leading = "leading" in options ? !!options.leading : leading; + trailing = "trailing" in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + leading, + trailing, + maxWait: wait, + }); + } + + /*! + * Wunderbaum - util + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + /** @module util */ + /** Readable names for `MouseEvent.button` */ + const MOUSE_BUTTONS = { + 0: "", + 1: "left", + 2: "middle", + 3: "right", + 4: "back", + 5: "forward", + }; + const MAX_INT = 9007199254740991; + const userInfo = _getUserInfo(); + /**True if the client is using a macOS platform. */ + const isMac = userInfo.isMac; + const REX_HTML = /[&<>"'/]/g; // Escape those characters + const REX_TOOLTIP = /[<>"'/]/g; // Don't escape `&` in tooltips + const ENTITY_MAP = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "/": "/", + }; + /** A generic error that can be thrown to indicate a validation error when + * handling the `apply` event for a node title or the `change` event for a + * grid cell. + */ + class ValidationError extends Error { + constructor(message) { + super(message); + this.name = "ValidationError"; + } + } + /** + * A ES6 Promise, that exposes the resolve()/reject() methods. + * + * TODO: See [Promise.withResolvers()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers#description) + * , a proposed standard, but not yet implemented in any browser. + */ + let Deferred$1 = class Deferred { + constructor() { + this.thens = []; + this.catches = []; + this.status = ""; + } + resolve(value) { + if (this.status) { + throw new Error("already settled"); + } + this.status = "resolved"; + this.resolvedValue = value; + this.thens.forEach((t) => t(value)); + this.thens = []; // Avoid memleaks. + } + reject(error) { + if (this.status) { + throw new Error("already settled"); + } + this.status = "rejected"; + this.rejectedError = error; + this.catches.forEach((c) => c(error)); + this.catches = []; // Avoid memleaks. + } + then(cb) { + if (status === "resolved") { + cb(this.resolvedValue); + } + else { + this.thens.unshift(cb); + } + } + catch(cb) { + if (this.status === "rejected") { + cb(this.rejectedError); + } + else { + this.catches.unshift(cb); + } + } + promise() { + return { + then: this.then, + catch: this.catch, + }; + } + }; + /**Throw an `Error` if `cond` is falsey. */ + function assert(cond, msg) { + if (!cond) { + msg = msg || "Assertion failed."; + throw new Error(msg); + } + } + function _getUserInfo() { + const nav = navigator; + // const ua = nav.userAgentData; + const res = { + isMac: /Mac/.test(nav.platform), + }; + return res; + } + /** Run `callback` when document was loaded. */ + function documentReady(callback) { + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", callback); + } + else { + callback(); + } + } + /** Resolve when document was loaded. */ + function documentReadyPromise() { + return new Promise((resolve) => { + documentReady(resolve); + }); + } + /** + * Iterate over Object properties or array elements. + * + * @param obj `Object`, `Array` or null + * @param callback(index, item) called for every item. + * `this` also contains the item. + * Return `false` to stop the iteration. + */ + function each(obj, callback) { + if (obj == null) { + // accept `null` or `undefined` + return obj; + } + const length = obj.length; + let i = 0; + if (typeof length === "number") { + for (; i < length; i++) { + if (callback.call(obj[i], i, obj[i]) === false) { + break; + } + } + } + else { + for (const k in obj) { + if (callback.call(obj[i], k, obj[k]) === false) { + break; + } + } + } + return obj; + } + /** Shortcut for `throw new Error(msg)`.*/ + function error(msg) { + throw new Error(msg); + } + /** Convert `<`, `>`, `&`, `"`, `'`, and `/` to the equivalent entities. */ + function escapeHtml(s) { + return ("" + s).replace(REX_HTML, function (s) { + return ENTITY_MAP[s]; + }); + } + // export function escapeRegExp(s: string) { + // return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + // } + /**Convert a regular expression string by escaping special characters (e.g. `"$"` -> `"\$"`) */ + function escapeRegex(s) { + return ("" + s).replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); + } + /** Convert `<`, `>`, `"`, `'`, and `/` (but not `&`) to the equivalent entities. */ + function escapeTooltip(s) { + return ("" + s).replace(REX_TOOLTIP, function (s) { + return ENTITY_MAP[s]; + }); + } + /** TODO */ + function extractHtmlText(s) { + if (s.indexOf(">") >= 0) { + error("Not implemented"); + // return $("
    ").html(s).text(); + } + return s; + } + /** + * Read the value from an HTML input element. + * + * If a `` is passed, the first child input is used. + * Depending on the target element type, `value` is interpreted accordingly. + * For example for a checkbox, a value of true, false, or null is returned if + * the element is checked, unchecked, or indeterminate. + * For datetime input control a numerical value is assumed, etc. + * + * Common use case: store the new user input in a `change` event handler: + * + * ```ts + * change: (e) => { + * const tree = e.tree; + * const node = e.node; + * // Read the value from the input control that triggered the change event: + * let value = tree.getValueFromElem(e.element); + * // and store it to the node model (assuming the column id matches the property name) + * node.data[e.info.colId] = value; + * }, + * ``` + * @param elem `` or `` or `` handle it + node.logDebug(`Ignored ${eventName} inside focused input`); + return; + } + // const curInputType = curInput.type || curInput.tagName; + // const breakoutKeys = INPUT_KEYS[curInputType]; + // if (!breakoutKeys.includes(eventName)) { + // node.logDebug(`Ignored ${eventName} inside ${curInputType} input`); + // return; + // } + } + else if (curInput) { + // On a cell that has an embedded, unfocused + if (eventName.length === 1 && inputCanFocus) { + // Typing a single char + curInput.focus(); + curInput.value = ""; + node.logDebug(`Focus input: ${eventName}`); + return false; + } + } + if (eventName === "Tab") { + eventName = "ArrowRight"; + handled = true; + } + else if (eventName === "Shift+Tab") { + eventName = tree.activeColIdx > 0 ? "ArrowLeft" : ""; + handled = true; + } + switch (eventName) { + case "+": + case "Add": + // case "=": // 187: '+' @ Chrome, Safari + node.setExpanded(true); + break; + case "-": + case "Subtract": + node.setExpanded(false); + break; + case " ": // Space + if (tree.activeColIdx === 0 && node.getOption("checkbox")) { + node.toggleSelected(); + handled = true; + } + else if (curInput && curInputType === "checkbox") { + curInput.click(); + // toggleCheckbox(curInput) + // new Event("change") + // curInput.change + handled = true; + } + break; + case "F2": + if (curInput && !inputHasFocus && inputCanFocus) { + curInput.focus(); + handled = true; + } + break; + case "Enter": + tree.setFocus(); // Blur prev. input if any + if ((tree.activeColIdx === 0 || isColspan) && node.isExpandable()) { + node.setExpanded(!node.isExpanded()); + handled = true; + } + else if (curInput && !inputHasFocus && inputCanFocus) { + curInput.focus(); + handled = true; + } + break; + case "Escape": + tree.setFocus(); // Blur prev. input if any + node.log(`keynav: focus tree...`); + if (tree.isCellNav() && navModeOption !== NavModeEnum.cell) { + node.log(`keynav: setCellNav(false)`); + tree.setCellNav(false); // row-nav mode + tree.setFocus(); // + handled = true; + } + break; + case "ArrowLeft": + tree.setFocus(); // Blur prev. input if any + if (isColspan && node.isExpanded()) { + node.setExpanded(false); + } + else if (!isColspan && tree.activeColIdx > 0) { + tree.setColumn(tree.activeColIdx - 1); + } + else if (navModeOption !== NavModeEnum.cell) { + tree.setCellNav(false); // row-nav mode + } + handled = true; + break; + case "ArrowRight": + tree.setFocus(); // Blur prev. input if any + if (isColspan && !node.isExpanded()) { + node.setExpanded(); + } + else if (!isColspan && + tree.activeColIdx < tree.columns.length - 1) { + tree.setColumn(tree.activeColIdx + 1); + } + handled = true; + break; + case "Home": // Generated by [Fn] + ArrowLeft on Mac + // case "Meta+ArrowLeft": + tree.setFocus(); // Blur prev. input if any + if (!isColspan && tree.activeColIdx > 0) { + tree.setColumn(0); + } + handled = true; + break; + case "End": // Generated by [Fn] + ArrowRight on Mac + // case "Meta+ArrowRight": + tree.setFocus(); // Blur prev. input if any + if (!isColspan && tree.activeColIdx < tree.columns.length - 1) { + tree.setColumn(tree.columns.length - 1); + } + handled = true; + break; + case "ArrowDown": + case "ArrowUp": + case "Backspace": + case "Control+End": // Generated by Control + [Fn] + ArrowRight on Mac + case "Control+Home": // Generated by Control + [Fn] + Arrowleft on Mac + case "Meta+ArrowDown": // [⌘] + ArrowDown on Mac + case "Meta+ArrowUp": // [⌘] + ArrowUp on Mac + case "PageDown": // Generated by [Fn] + ArrowDown on Mac + case "PageUp": // Generated by [Fn] + ArrowUp on Mac + node.navigate(eventName, { activate: activate, event: event }); + // if (isCellEditMode) { + // this._getEmbeddedInputElem(null, true); // set focus to input + // } + handled = true; + break; + default: + handled = false; + } + } + if (handled) { + event.preventDefault(); + } + return; + } + } + + /*! + * Wunderbaum - ext-logger + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + class LoggerExtension extends WunderbaumExtension { + constructor(tree) { + super(tree, "logger", {}); + this.ignoreEvents = new Set([ + "iconBadge", + // "enhanceTitle", + "render", + "discard", + ]); + this.prefix = tree + ".ext-logger"; + } + init() { + const tree = this.tree; + // this.ignoreEvents.add(); + if (tree.getOption("debugLevel") >= 4) { + // const self = this; + const ignoreEvents = this.ignoreEvents; + const prefix = this.prefix; + overrideMethod(tree, "callEvent", function (name, extra) { + /* eslint-disable prefer-rest-params */ + if (ignoreEvents.has(name)) { + return tree._superApply(arguments); + } + const start = Date.now(); + const res = tree._superApply(arguments); + tree.logDebug(`${prefix}: callEvent('${name}') took ${Date.now() - start} ms.`, arguments[1]); + return res; + }); + } + } + onKeyEvent(data) { + // this.tree.logInfo("onKeyEvent", eventToString(data.event), data); + this.tree.logDebug(`${this.prefix}: onKeyEvent()`, data); + return; + } + } + + /*! + * Wunderbaum - common + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + const DEFAULT_DEBUGLEVEL = 3; // Replaced by rollup script + /** + * Fixed height of a row in pixel. Must match the SCSS variable `$row-outer-height`. + */ + const ROW_HEIGHT = 22; + /** + * Fixed width of node icons in pixel. Must match the SCSS variable `$icon-outer-width`. + */ + const ICON_WIDTH = 20; + /** + * Adjust the width of the title span, so overflow ellipsis work. + * (2 x `$col-padding-x` + 3px rounding errors). + */ + const TITLE_SPAN_PAD_Y = 7; + /** Render row markup for N nodes above and below the visible viewport. */ + const RENDER_MAX_PREFETCH = 5; + /** Regular expression to detect if a string describes an image URL (in contrast + * to a class name). Strings are considered image urls if they contain '.' or '/'. + */ + const TEST_IMG = new RegExp(/\.|\//); + // export const RECURSIVE_REQUEST_ERROR = "$recursive_request"; + // export const INVALID_REQUEST_TARGET_ERROR = "$request_target_invalid"; + /** + * Default node icons. + * Requires bootstrap icons https://icons.getbootstrap.com + */ + const iconMaps = { + bootstrap: { + error: "bi bi-exclamation-triangle", + // loading: "bi bi-hourglass-split wb-busy", + loading: "bi bi-chevron-right wb-busy", + // loading: "bi bi-arrow-repeat wb-spin", + // loading: '
    Loading...
    ', + // noData: "bi bi-search", + noData: "bi bi-question-circle", + expanderExpanded: "bi bi-chevron-down", + // expanderExpanded: "bi bi-dash-square", + expanderCollapsed: "bi bi-chevron-right", + // expanderCollapsed: "bi bi-plus-square", + expanderLazy: "bi bi-chevron-right wb-helper-lazy-expander", + // expanderLazy: "bi bi-chevron-bar-right", + checkChecked: "bi bi-check-square", + checkUnchecked: "bi bi-square", + checkUnknown: "bi bi-dash-square-dotted", + radioChecked: "bi bi-circle-fill", + radioUnchecked: "bi bi-circle", + radioUnknown: "bi bi-record-circle", + folder: "bi bi-folder2", + folderOpen: "bi bi-folder2-open", + folderLazy: "bi bi-folder-symlink", + doc: "bi bi-file-earmark", + }, + fontawesome6: { + error: "fa-solid fa-triangle-exclamation", + loading: "fa-solid fa-chevron-right fa-beat", + noData: "fa-solid fa-circle-question", + expanderExpanded: "fa-solid fa-chevron-down", + expanderCollapsed: "fa-solid fa-chevron-right", + expanderLazy: "fa-solid fa-chevron-right wb-helper-lazy-expander", + checkChecked: "fa-regular fa-square-check", + checkUnchecked: "fa-regular fa-square", + checkUnknown: "fa-regular fa-square-minus", + radioChecked: "fa-solid fa-circle", + radioUnchecked: "fa-regular fa-circle", + radioUnknown: "fa-regular fa-circle-question", + folder: "fa-solid fa-folder-closed", + folderOpen: "fa-regular fa-folder-open", + folderLazy: "fa-solid fa-folder-plus", + doc: "fa-regular fa-file", + }, + }; + /** Dict keys that are evaluated by source loader (others are added to `tree.data` instead). */ + const RESERVED_TREE_SOURCE_KEYS = new Set([ + "_format", + "_keyMap", + "_positional", + "_typeList", + "_valueMap", + "_version", + "children", + "columns", + "types", + ]); + // /** Key codes that trigger grid navigation, even when inside an input element. */ + // export const INPUT_BREAKOUT_KEYS: Set = new Set([ + // // "ArrowDown", + // // "ArrowUp", + // "Enter", + // "Escape", + // ]); + /** Map `KeyEvent.key` to navigation action. */ + const KEY_TO_ACTION_DICT = { + " ": "toggleSelect", + "+": "expand", + Add: "expand", + ArrowDown: "down", + ArrowLeft: "left", + ArrowRight: "right", + ArrowUp: "up", + Backspace: "parent", + "/": "collapseAll", + Divide: "collapseAll", + End: "lastCol", + Home: "firstCol", + "Control+End": "last", + "Control+Home": "first", + "Meta+ArrowDown": "last", + "Meta+ArrowUp": "first", + "*": "expandAll", + Multiply: "expandAll", + PageDown: "pageDown", + PageUp: "pageUp", + "-": "collapse", + Subtract: "collapse", + }; + /** Return a callback that returns true if the node title matches the string + * or regular expression. + * @see {@link WunderbaumNode.findAll()} + */ + function makeNodeTitleMatcher(match) { + if (match instanceof RegExp) { + return function (node) { + return match.test(node.title); + }; + } + assert(typeof match === "string", `Expected a string or RegExp: ${match}`); + // s = escapeRegex(s.toLowerCase()); + return function (node) { + return node.title === match; + // console.log("match " + node, node.title.toLowerCase().indexOf(match)) + // return node.title.toLowerCase().indexOf(match) >= 0; + }; + } + /** Return a callback that returns true if the node title starts with a string (case-insensitive). */ + function makeNodeTitleStartMatcher(s) { + s = escapeRegex(s); + const reMatch = new RegExp("^" + s, "i"); + return function (node) { + return reMatch.test(node.title); + }; + } + /** Compare two nodes by title (case-insensitive). */ + function nodeTitleSorter(a, b) { + const x = a.title.toLowerCase(); + const y = b.title.toLowerCase(); + return x === y ? 0 : x > y ? 1 : -1; + } + /** + * Convert 'flat' to 'nested' format. + * + * Flat node entry format: + * [PARENT_ID, [POSITIONAL_ARGS]] + * or + * [PARENT_ID, [POSITIONAL_ARGS], {KEY_VALUE_ARGS}] + * + * 1. Parent-referencing list is converted to a list of nested dicts with + * optional `children` properties. + * 2. `[POSITIONAL_ARGS]` are added as dict attributes. + */ + function unflattenSource(source) { + var _a, _b, _c; + const { _format, _keyMap = {}, _positional = [], children } = source; + if (_format !== "flat") { + throw new Error(`Expected source._format: "flat", but got ${_format}`); + } + if (_positional && _positional.includes("children")) { + throw new Error(`source._positional must not include "children": ${_positional}`); + } + let longToShort = _keyMap; + if (_keyMap.t) { + // Inverse keyMap was used (pre 0.7.0) + // TODO: raise Error on final 1.x release + const msg = `source._keyMap maps from long to short since v0.7.0. Flip key/value!`; + console.warn(msg); // eslint-disable-line no-console + longToShort = {}; + for (const [key, value] of Object.entries(_keyMap)) { + longToShort[value] = key; + } + } + const positionalShort = _positional.map((e) => longToShort[e]); + const newChildren = []; + const keyToNodeMap = {}; + const indexToNodeMap = {}; + const keyAttrName = (_a = longToShort["key"]) !== null && _a !== void 0 ? _a : "key"; + const childrenAttrName = (_b = longToShort["children"]) !== null && _b !== void 0 ? _b : "children"; + for (const [index, nodeTuple] of children.entries()) { + // Node entry format: + // [PARENT_ID, [POSITIONAL_ARGS]] + // or + // [PARENT_ID, [POSITIONAL_ARGS], {KEY_VALUE_ARGS}] + const [parentId, args, kwargs = {}] = nodeTuple; + // Free up some memory as we go + nodeTuple[1] = null; + if (nodeTuple[2] != null) { + nodeTuple[2] = null; + } + // console.log("flatten", parentId, args, kwargs) + // We keep `kwargs` as our new node definition. Then we add all positional + // values to this object: + args.forEach((val, positionalIdx) => { + kwargs[positionalShort[positionalIdx]] = val; + }); + // Find the parent node. `null` means 'toplevel'. PARENT_ID may be the numeric + // index of the source.children list. If PARENT_ID is a string, we search + // a parent with node.key of this value. + indexToNodeMap[index] = kwargs; + const key = kwargs[keyAttrName]; + if (key != null) { + keyToNodeMap[key] = kwargs; + } + let parentNode = null; + if (parentId === null) ; + else if (typeof parentId === "number") { + parentNode = indexToNodeMap[parentId]; + if (parentNode === undefined) { + throw new Error(`unflattenSource: Could not find parent node by index: ${parentId}.`); + } + } + else { + parentNode = keyToNodeMap[parentId]; + if (parentNode === undefined) { + throw new Error(`unflattenSource: Could not find parent node by key: ${parentId}`); + } + } + if (parentNode) { + (_c = parentNode[childrenAttrName]) !== null && _c !== void 0 ? _c : (parentNode[childrenAttrName] = []); + parentNode[childrenAttrName].push(kwargs); + } + else { + newChildren.push(kwargs); + } + } + source.children = newChildren; + } + /** + * Decompresses the source data by + * - converting from 'flat' to 'nested' format + * - expanding short alias names to long names (if defined in _keyMap) + * - resolving value indexes to value strings (if defined in _valueMap) + * + * @param source - The source object to be decompressed. + * @returns void + */ + function decompressSourceData(source) { + let { _format, _version = 1, _keyMap, _valueMap } = source; + assert(_version === 1, `Expected file version 1 instead of ${_version}`); + let longToShort = _keyMap; + let shortToLong = {}; + if (longToShort) { + for (const [key, value] of Object.entries(longToShort)) { + shortToLong[value] = key; + } + } + // Fallback for old format (pre 0.7.0, using _keyMap in reverse direction) + // TODO: raise Error on final 1.x release + if (longToShort && longToShort.t) { + const msg = `source._keyMap maps from long to short since v0.7.0. Flip key/value!`; + console.warn(msg); // eslint-disable-line no-console + [longToShort, shortToLong] = [shortToLong, longToShort]; + } + // Fallback for old format (pre 0.7.0, using _typeList instead of _valueMap) + // TODO: raise Error on final 1.x release + if (source._typeList != null) { + const msg = `source._typeList is deprecated since v0.7.0: use source._valueMap: {"type": [...]} instead.`; + if (_valueMap != null) { + throw new Error(msg); + } + else { + console.warn(msg); // eslint-disable-line no-console + _valueMap = { type: source._typeList }; + delete source._typeList; + } + } + if (_format === "flat") { + unflattenSource(source); + } + delete source._format; + delete source._version; + delete source._keyMap; + delete source._valueMap; + delete source._positional; + function _iter(childList) { + for (const node of childList) { + // Iterate over a list of names, because we modify inside the loop + // (for ... of ... does not allow this) + Object.getOwnPropertyNames(node).forEach((propName) => { + const value = node[propName]; + // Replace short names with long names if defined in _keyMap + let longName = propName; + if (_keyMap && shortToLong[propName] != null) { + longName = shortToLong[propName]; + if (longName !== propName) { + node[longName] = value; + delete node[propName]; + } + } + // Replace type index with type name if defined in _valueMap + if (_valueMap && + typeof value === "number" && + _valueMap[longName] != null) { + const newValue = _valueMap[longName][value]; + if (newValue == null) { + throw new Error(`Expected valueMap[${longName}][${value}] entry in [${_valueMap[longName]}]`); + } + node[longName] = newValue; + } + }); + // Recursion + if (node.children) { + _iter(node.children); + } + } + } + if (_keyMap || _valueMap) { + _iter(source.children); + } + } + + /*! + * Wunderbaum - ext-dnd + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + const nodeMimeType = "application/x-wunderbaum-node"; + class DndExtension extends WunderbaumExtension { + constructor(tree) { + super(tree, "dnd", { + autoExpandMS: 1500, + // dropMarkerInsertOffsetX: -16, // Additional offset for drop-marker with hitMode = "before"/"after" + // dropMarkerOffsetX: -24, // Absolute position offset for .fancytree-drop-marker relatively to ..fancytree-title (icon/img near a node accepting drop) + // #1021 `document.body` is not available yet + // dropMarkerParent: "body", // Root Container used for drop marker (could be a shadow root) + multiSource: false, + effectAllowed: "all", + dropEffectDefault: "move", + guessDropEffect: true, + preventForeignNodes: false, + preventLazyParents: true, + preventNonNodes: false, + preventRecursion: true, + preventSameParent: false, + preventVoidMoves: true, + serializeClipboardData: true, + scroll: true, + scrollSensitivity: 20, + // scrollnterval: 50, // Generate event every 50 ms + scrollSpeed: 5, + // setTextTypeJson: false, // Allow dragging of nodes to different IE windows + sourceCopyHook: null, + // Events (drag support) + dragStart: null, + drag: null, + dragEnd: null, + // Events (drop support) + dragEnter: null, + dragOver: null, + dragExpand: null, + drop: null, + dragLeave: null, // Callback(targetNode, data) + }); + // public dropMarkerElem?: HTMLElement; + this.srcNode = null; + this.lastTargetNode = null; + this.lastEnterStamp = 0; + this.lastAllowedDropRegions = null; + this.lastDropEffect = null; + this.lastDropRegion = false; + this.currentScrollDir = 0; + this.applyScrollDirThrottled = throttle(this._applyScrollDir, 50); + } + init() { + super.init(); + // Store the current scroll parent, which may be the tree + // container, any enclosing div, or the document. + // #761: scrollParent() always needs a container child + // $temp = $("").appendTo(this.$container); + // this.$scrollParent = $temp.scrollParent(); + // $temp.remove(); + const tree = this.tree; + const dndOpts = tree.options.dnd; + // Enable drag support if dragStart() is specified: + if (dndOpts.dragStart) { + onEvent(tree.element, "dragstart drag dragend", this.onDragEvent.bind(this)); + } + // Enable drop support if dragEnter() is specified: + if (dndOpts.dragEnter) { + onEvent(tree.element, "dragenter dragover dragleave drop", this.onDropEvent.bind(this)); + } + } + /** Cleanup classes after target node is no longer hovered. */ + _leaveNode() { + // We remove the marker on dragenter from the previous target: + const ltn = this.lastTargetNode; + this.lastEnterStamp = 0; + if (ltn) { + ltn.setClass("wb-drop-target wb-drop-over wb-drop-after wb-drop-before", false); + this.lastTargetNode = null; + } + } + /** */ + unifyDragover(res) { + if (res === false) { + return false; + } + else if (res instanceof Set) { + return res.size > 0 ? res : false; + } + else if (res === true) { + return new Set(["over", "before", "after"]); + } + else if (typeof res === "string" || isArray(res)) { + res = toSet(res); + return res.size > 0 ? res : false; + } + throw new Error("Unsupported drop region definition: " + res); + } + /** + * Calculates the drop region based on the drag event and the allowed drop regions. + */ + _calcDropRegion(e, allowed) { + const dy = e.offsetY; + if (!allowed) { + return false; + } + else if (allowed.size === 3) { + return dy < 0.25 * ROW_HEIGHT + ? "before" + : dy > 0.75 * ROW_HEIGHT + ? "after" + : "over"; + } + else if (allowed.size === 1 && allowed.has("over")) { + return "over"; + } + else { + // Only 'before' and 'after': + return dy > ROW_HEIGHT / 2 ? "after" : "before"; + } + // return "over"; + } + /** + * Guess drop effect (copy/link/move) using opinionated conventions. + * + * Default: dnd.dropEffectDefault + */ + _guessDropEffect(e) { + // const nativeDropEffect = e.dataTransfer?.dropEffect; + var _a; + // if (nativeDropEffect && nativeDropEffect !== "none") { + // return nativeDropEffect; + // } + const dndOpts = this.treeOpts.dnd; + const ea = (_a = dndOpts.effectAllowed) !== null && _a !== void 0 ? _a : "all"; + const canCopy = ["all", "copy", "copyLink", "copyMove"].includes(ea); + const canLink = ["all", "link", "copyLink", "linkMove"].includes(ea); + const canMove = ["all", "move", "copyMove", "linkMove"].includes(ea); + let res = dndOpts.dropEffectDefault; + if (dndOpts.guessDropEffect) { + if (isMac) { + if (e.altKey && canCopy) { + res = "copy"; + } + if (e.metaKey && canMove) { + res = "move"; // command key + } + if (e.altKey && e.metaKey && canLink) { + res = "link"; + } + } + else { + if (e.ctrlKey && canCopy) { + res = "copy"; + } + if (e.shiftKey && canMove) { + res = "move"; + } + if (e.altKey && canLink) { + res = "link"; + } + } + } + return res; + } + /** Don't allow void operation ('drop on self').*/ + _isVoidDrop(targetNode, srcNode, dropRegion) { + // this.tree.logDebug( + // `_isVoidDrop: ${srcNode} -> ${dropRegion} ${targetNode}` + // ); + // TODO: should be checked on move only + if (!this.treeOpts.dnd.preventVoidMoves || !srcNode) { + return false; + } + if ((dropRegion === "before" && targetNode === srcNode.getNextSibling()) || + (dropRegion === "after" && targetNode === srcNode.getPrevSibling())) { + // this.tree.logDebug("Prevented before/after self"); + return true; + } + // Don't allow dropping nodes on own parent (or self) + return srcNode === targetNode || srcNode.parent === targetNode; + } + /* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */ + _applyScrollDir() { + if (this.isDragging() && this.currentScrollDir) { + const dndOpts = this.tree.options.dnd; + const sp = this.tree.element; // scroll parent + const scrollTop = sp.scrollTop; + if (this.currentScrollDir < 0) { + sp.scrollTop = Math.max(0, scrollTop - dndOpts.scrollSpeed); + } + else if (this.currentScrollDir > 0) { + sp.scrollTop = scrollTop + dndOpts.scrollSpeed; + } + } + } + /* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */ + _autoScroll(viewportY) { + const tree = this.tree; + const dndOpts = tree.options.dnd; + const sensitivity = dndOpts.scrollSensitivity; + const sp = tree.element; // scroll parent + const headerHeight = tree.headerElement.clientHeight; // May be 0 + // const height = sp.clientHeight - headerHeight; + // const height = sp.offsetHeight + headerHeight; + const height = sp.offsetHeight; + const scrollTop = sp.scrollTop; + // tree.logDebug( + // `autoScroll: height=${height}, scrollTop=${scrollTop}, viewportY=${viewportY}` + // ); + this.currentScrollDir = 0; + if (scrollTop > 0 && + viewportY > 0 && + viewportY <= sensitivity + headerHeight) { + // Mouse in top 20px area: scroll up + // sp.scrollTop = Math.max(0, scrollTop - dndOpts.scrollSpeed); + this.currentScrollDir = -1; + } + else if (scrollTop < sp.scrollHeight - height && + viewportY >= height - sensitivity) { + // Mouse in bottom 20px area: scroll down + // sp.scrollTop = scrollTop + dndOpts.scrollSpeed; + this.currentScrollDir = +1; + } + if (this.currentScrollDir) { + this.applyScrollDirThrottled(); + } + return sp.scrollTop - scrollTop; + } + /** Return true if a drag operation currently in progress. */ + isDragging() { + return !!this.srcNode; + } + /** + * Handle dragstart, drag and dragend events for the source node. + */ + onDragEvent(e) { + var _a; + // const tree = this.tree; + const dndOpts = this.treeOpts.dnd; + const srcNode = Wunderbaum.getNode(e); + if (!srcNode) { + this.tree.logWarn(`onDragEvent.${e.type}: no node`); + return; + } + if (["dragstart", "dragend"].includes(e.type)) { + this.tree.logDebug(`onDragEvent.${e.type} srcNode: ${srcNode}`, e); + } + // --- dragstart --- + if (e.type === "dragstart") { + // Set a default definition of allowed effects + e.dataTransfer.effectAllowed = dndOpts.effectAllowed; //"copyMove"; // "all"; + if (srcNode.isEditingTitle()) { + srcNode.logDebug("Prevented dragging node in edit mode."); + e.preventDefault(); + return false; + } + // Let user cancel the drag operation, override effectAllowed, etc.: + const res = srcNode._callEvent("dnd.dragStart", { event: e }); + if (!res) { + e.preventDefault(); + return false; + } + const nodeData = srcNode.toDict(true, (n) => { + // We don't want to re-use the key on drop: + n._orgKey = n.key; + delete n.key; + }); + nodeData._treeId = srcNode.tree.id; + if (dndOpts.serializeClipboardData) { + if (typeof dndOpts.serializeClipboardData === "function") { + e.dataTransfer.setData(nodeMimeType, dndOpts.serializeClipboardData(nodeData, srcNode)); + } + else { + e.dataTransfer.setData(nodeMimeType, JSON.stringify(nodeData)); + } + } + // e.dataTransfer!.setData("text/html", $(node.span).html()); + if (!((_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.types.includes("text/plain"))) { + e.dataTransfer.setData("text/plain", srcNode.title); + } + this.srcNode = srcNode; + setTimeout(() => { + // Decouple this call, so the CSS is applied to the node, but not to + // the system generated drag image + srcNode.setClass("wb-drag-source"); + }, 0); + // --- drag --- + } + else if (e.type === "drag") { + if (dndOpts.drag) { + srcNode._callEvent("dnd.drag", { event: e }); + } + // --- dragend --- + } + else if (e.type === "dragend") { + srcNode.setClass("wb-drag-source", false); + this.srcNode = null; + if (this.lastTargetNode) { + this._leaveNode(); + } + srcNode._callEvent("dnd.dragEnd", { event: e }); + } + return true; + } + /** + * Handle dragenter, dragover, dragleave, drop events. + */ + onDropEvent(e) { + var _a; + // const isLink = event.dataTransfer.types.includes("text/uri-list"); + const srcNode = this.srcNode; + const srcTree = srcNode ? srcNode.tree : null; + const targetNode = Wunderbaum.getNode(e); + const dndOpts = this.treeOpts.dnd; + const dt = e.dataTransfer; + const dropRegion = this._calcDropRegion(e, this.lastAllowedDropRegions); + /** Helper to log a message if predicate is false. */ + const _t = (pred, msg) => { + if (pred) { + this.tree.log(`Prevented drop operation (${msg}).`); + } + return pred; + }; + if (!targetNode) { + this._leaveNode(); + return; + } + if (["drop"].includes(e.type)) { + this.tree.logDebug(`onDropEvent.${e.type} targetNode: ${targetNode}, ea: ${dt === null || dt === void 0 ? void 0 : dt.effectAllowed}, ` + + `de: ${dt === null || dt === void 0 ? void 0 : dt.dropEffect}, cy: ${e.offsetY}, r: ${dropRegion}, srcNode: ${srcNode}`, e); + } + // --- dragenter --- + if (e.type === "dragenter") { + // this.tree.logWarn(` onDropEvent.${e.type} targetNode: ${targetNode}`, e); + this.lastAllowedDropRegions = null; + // `dragleave` is not reliable with event delegation, so we generate it + // from dragenter: + if (this.lastTargetNode && this.lastTargetNode !== targetNode) { + this._leaveNode(); + } + this.lastTargetNode = targetNode; + this.lastEnterStamp = Date.now(); + if ( + // Don't drop on status node: + _t(targetNode.isStatusNode(), "is status node") || + // Prevent dropping nodes from different Wunderbaum trees: + _t(dndOpts.preventForeignNodes && targetNode.tree !== srcTree, "preventForeignNodes") || + // Prevent dropping items on unloaded lazy Wunderbaum tree nodes: + _t(dndOpts.preventLazyParents && !targetNode.isLoaded(), "preventLazyParents") || + // Prevent dropping items other than Wunderbaum tree nodes: + _t(dndOpts.preventNonNodes && !srcNode, "preventNonNodes") || + // Prevent dropping nodes on own descendants: + _t(dndOpts.preventRecursion && (srcNode === null || srcNode === void 0 ? void 0 : srcNode.isAncestorOf(targetNode)), "preventRecursion") || + // Prevent dropping nodes under same direct parent: + _t(dndOpts.preventSameParent && + srcNode && + targetNode.parent === srcNode.parent, "preventSameParent") || + // Don't allow void operation ('drop on self'): TODO: should be checked on move only + _t(dndOpts.preventVoidMoves && targetNode === srcNode, "preventVoidMoves")) { + dt.dropEffect = "none"; + // this.tree.log("Prevented drop operation"); + return true; // Prevent drop operation + } + // User may return a set of regions (or `false` to prevent drop) + // Figure out a drop effect (copy/link/move) using opinated conventions. + dt.dropEffect = this._guessDropEffect(e) || "none"; + let regionSet = targetNode._callEvent("dnd.dragEnter", { + event: e, + sourceNode: srcNode, + }); + // + regionSet = this.unifyDragover(regionSet); + if (!regionSet) { + dt.dropEffect = "none"; + return true; // Prevent drop operation + } + this.lastAllowedDropRegions = regionSet; + this.lastDropEffect = dt.dropEffect; + targetNode.setClass("wb-drop-target"); + e.preventDefault(); // Allow drop (Drop operation is denied by default) + return false; + // --- dragover --- + } + else if (e.type === "dragover") { + const viewportY = e.clientY - this.tree.element.offsetTop; + this._autoScroll(viewportY); + dt.dropEffect = this._guessDropEffect(e) || "none"; + targetNode._callEvent("dnd.dragOver", { event: e, sourceNode: srcNode }); + const region = this._calcDropRegion(e, this.lastAllowedDropRegions); + this.lastDropRegion = region; + this.lastDropEffect = dt.dropEffect; + if (dndOpts.autoExpandMS > 0 && + targetNode.isExpandable(true) && + !targetNode._isLoading && + Date.now() - this.lastEnterStamp > dndOpts.autoExpandMS && + targetNode._callEvent("dnd.dragExpand", { + event: e, + sourceNode: srcNode, + }) !== false) { + targetNode.setExpanded(); + } + if (!region || this._isVoidDrop(targetNode, srcNode, region)) { + return; // We already rejected in dragenter + } + targetNode.setClass("wb-drop-over", region === "over"); + targetNode.setClass("wb-drop-before", region === "before"); + targetNode.setClass("wb-drop-after", region === "after"); + e.preventDefault(); // Allow drop (Drop operation is denied by default) + return false; + // --- dragleave --- + } + else if (e.type === "dragleave") { + // NOTE: we cannot trust this event, since it is always fired, + // Instead we remove the marker on dragenter + targetNode._callEvent("dnd.dragLeave", { event: e, sourceNode: srcNode }); + // --- drop --- + } + else if (e.type === "drop") { + e.stopPropagation(); // prevent browser from opening links? + e.preventDefault(); // #69 prevent iOS browser from opening links + this._leaveNode(); + const region = this.lastDropRegion; + let nodeData = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData(nodeMimeType); + nodeData = nodeData ? JSON.parse(nodeData) : null; + const srcNode = this.srcNode; + const lastDropEffect = this.lastDropEffect; + setTimeout(() => { + // Decouple this call, because drop actions may prevent the dragend event + // from being fired on some browsers + targetNode._callEvent("dnd.drop", { + event: e, + region: region, + suggestedDropMode: region === "over" ? "appendChild" : region, + suggestedDropEffect: lastDropEffect, + // suggestedDropEffect: e.dataTransfer?.dropEffect, + sourceNode: srcNode, + sourceNodeData: nodeData, + }); + }, 10); + } + return false; + } + } + + /*! + * Wunderbaum - drag_observer + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + /** + * Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'. + */ + class DragObserver { + constructor(opts) { + this.start = { + x: 0, + y: 0, + altKey: false, + ctrlKey: false, + metaKey: false, + shiftKey: false, + }; + this.dragElem = null; + this.dragging = false; + // TODO: touch events + this.events = ["mousedown", "mouseup", "mousemove", "keydown"]; + if (!opts.root) { + throw new Error("Missing `root` option."); + } + this.opts = Object.assign({ thresh: 5 }, opts); + this.root = opts.root; + this._handler = this.handleEvent.bind(this); + this.events.forEach((type) => { + this.root.addEventListener(type, this._handler); + }); + } + /** Unregister all event listeners. */ + disconnect() { + this.events.forEach((type) => { + this.root.removeEventListener(type, this._handler); + }); + } + getDragElem() { + return this.dragElem; + } + isDragging() { + return this.dragging; + } + stopDrag(cb_event) { + if (this.dragging && this.opts.dragstop && cb_event) { + cb_event.type = "dragstop"; + this.opts.dragstop(cb_event); + } + this.dragElem = null; + this.dragging = false; + } + handleEvent(e) { + const type = e.type; + const opts = this.opts; + const cb_event = { + type: e.type, + event: e, + dragElem: this.dragElem, + dx: e.pageX - this.start.x, + dy: e.pageY - this.start.y, + apply: undefined, + }; + switch (type) { + case "keydown": + this.stopDrag(cb_event); + break; + case "mousedown": + if (this.dragElem) { + this.stopDrag(cb_event); + break; + } + if (opts.selector) { + let elem = e.target; + if (elem.matches(opts.selector)) { + this.dragElem = elem; + } + else { + elem = elem.closest(opts.selector); + if (elem) { + this.dragElem = elem; + } + else { + break; // no event delegation selector matched + } + } + } + this.start.x = e.pageX; + this.start.y = e.pageY; + this.start.altKey = e.altKey; + this.start.ctrlKey = e.ctrlKey; + this.start.metaKey = e.metaKey; + this.start.shiftKey = e.shiftKey; + break; + case "mousemove": + // TODO: debounce/throttle? + // TODO: horizontal mode: ignore if dx unchanged + if (!this.dragElem) { + break; + } + if (!this.dragging) { + if (opts.thresh) { + const dist2 = cb_event.dx * cb_event.dx + cb_event.dy * cb_event.dy; + if (dist2 < opts.thresh * opts.thresh) { + break; + } + } + cb_event.type = "dragstart"; + if (opts.dragstart(cb_event) === false) { + this.stopDrag(cb_event); + break; + } + this.dragging = true; + } + if (this.dragging && this.opts.drag) { + cb_event.type = "drag"; + this.opts.drag(cb_event); + } + break; + case "mouseup": + if (!this.dragging) { + this.stopDrag(cb_event); + break; + } + if (e.button === 0) { + cb_event.apply = true; + } + else { + cb_event.apply = false; + } + this.stopDrag(cb_event); + break; + } + } + } + + /*! + * Wunderbaum - ext-grid + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + class GridExtension extends WunderbaumExtension { + constructor(tree) { + super(tree, "grid", { + // throttle: 200, + }); + this.observer = new DragObserver({ + root: window.document, + selector: "span.wb-col-resizer", + thresh: 4, + // throttle: 400, + dragstart: (e) => { + return this.tree.element.contains(e.dragElem); + }, + drag: (e) => { + // TODO: throttle + return this.handleDrag(e); + }, + dragstop: (e) => { + return this.handleDrag(e); + }, + }); + } + init() { + super.init(); + } + handleDrag(e) { + const info = Wunderbaum.getEventInfo(e.event); + // this.tree.options. + this.tree.log(`${e.type}(${e.dx})`, e, info); + } + } + + /*! + * Wunderbaum - deferred + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + /** + * Implement a ES6 Promise, that exposes a resolve() and reject() method. + * + * Loosely mimics {@link https://api.jquery.com/category/deferred-object/ | jQuery.Deferred}. + * Example: + * ```js + * function foo() { + * let dfd = new Deferred(), + * ... + * dfd.resolve('foo') + * ... + * return dfd.promise(); + * } + * ``` + */ + class Deferred { + constructor() { + this._promise = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + } + /** Resolve the Promise. */ + resolve(value) { + this._resolve(value); + } + /** Reject the Promise. */ + reject(reason) { + this._reject(reason); + } + /** Return the native Promise instance.*/ + promise() { + return this._promise; + } + /** Call Promise.then on the embedded promise instance.*/ + then(cb) { + return this._promise.then(cb); + } + /** Call Promise.catch on the embedded promise instance.*/ + catch(cb) { + return this._promise.catch(cb); + } + /** Call Promise.finally on the embedded promise instance.*/ + finally(cb) { + return this._promise.finally(cb); + } + } + + /*! + * Wunderbaum - wunderbaum_node + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + /** WunderbaumNode properties that can be passed with source data. + * (Any other source properties will be stored as `node.data.PROP`.) + */ + const NODE_PROPS = new Set([ + "checkbox", + "classes", + "expanded", + "icon", + "iconTooltip", + "key", + "lazy", + "_partsel", + "radiogroup", + "refKey", + "selected", + "statusNodeType", + "title", + "tooltip", + "type", + "unselectable", + ]); + /** WunderbaumNode properties that will be returned by `node.toDict()`.) + */ + const NODE_DICT_PROPS = new Set(NODE_PROPS); + NODE_DICT_PROPS.delete("_partsel"); + NODE_DICT_PROPS.delete("unselectable"); + /** + * A single tree node. + * + * **NOTE:**
    + * Generally you should not modify properties directly, since this may break + * the internal bookkeeping. + */ + class WunderbaumNode { + constructor(tree, parent, data) { + var _a, _b; + /** Reference key. Unlike {@link key}, a `refKey` may occur multiple + * times within a tree (in this case we have 'clone nodes'). + * @see Use {@link setKey} to modify. + */ + this.refKey = undefined; + this.children = null; + /** Additional classes added to `div.wb-row`. + * @see {@link hasClass}, {@link setClass}. */ + this.classes = null; //new Set(); + /** Custom data that was passed to the constructor */ + this.data = {}; + this._isLoading = false; + this._requestId = 0; + this._errorInfo = null; + this._partsel = false; + this._partload = false; + this.subMatchCount = 0; + this._rowIdx = 0; + this._rowElem = undefined; + assert(!parent || parent.tree === tree, `Invalid parent: ${parent}`); + assert(!data.children, "'children' not allowed here"); + this.tree = tree; + this.parent = parent; + this.key = "" + ((_a = data.key) !== null && _a !== void 0 ? _a : ++WunderbaumNode.sequence); + this.title = "" + ((_b = data.title) !== null && _b !== void 0 ? _b : "<" + this.key + ">"); + data.refKey != null ? (this.refKey = "" + data.refKey) : 0; + data.type != null ? (this.type = "" + data.type) : 0; + this.expanded = data.expanded === true; + data.icon != null ? (this.icon = data.icon) : 0; + this.lazy = data.lazy === true; + data.statusNodeType != null + ? (this.statusNodeType = ("" + data.statusNodeType)) + : 0; + data.colspan != null ? (this.colspan = !!data.colspan) : 0; + // Selection + data.checkbox != null ? (this.checkbox = !!data.checkbox) : 0; + data.radiogroup != null ? (this.radiogroup = !!data.radiogroup) : 0; + this.selected = data.selected === true; + data.unselectable === true ? (this.unselectable = true) : 0; + if (data.classes) { + this.setClass(data.classes); + } + // Store custom fields as `node.data` + for (const [key, value] of Object.entries(data)) { + if (!NODE_PROPS.has(key)) { + this.data[key] = value; + } + } + if (parent && !this.statusNodeType) { + // Don't register root node or status nodes + tree._registerNode(this); + } + } + /** + * Return readable string representation for this instance. + * @internal + */ + toString() { + return `WunderbaumNode@${this.key}<'${this.title}'>`; + } + /** + * Iterate all descendant nodes depth-first, pre-order using `for ... of ...` syntax. + * More concise, but slightly slower than {@link WunderbaumNode.visit}. + * + * Example: + * ```js + * for(const n of node) { + * ... + * } + * ``` + */ + *[Symbol.iterator]() { + // let node: WunderbaumNode | null = this; + const cl = this.children; + if (cl) { + for (let i = 0, l = cl.length; i < l; i++) { + const n = cl[i]; + yield n; + if (n.children) { + yield* n; + } + } + // Slower: + // for (let node of this.children) { + // yield node; + // yield* node : 0; + // } + } + } + // /** Return an option value. */ + // protected _getOpt( + // name: string, + // nodeObject: any = null, + // treeOptions: any = null, + // defaultValue: any = null + // ): any { + // return evalOption( + // name, + // this, + // nodeObject || this, + // treeOptions || this.tree.options, + // defaultValue + // ); + // } + /** Call event handler if defined in tree.options. + * Example: + * ```js + * node._callEvent("edit.beforeEdit", {foo: 42}) + * ``` + */ + _callEvent(type, extra) { + return this.tree._callEvent(type, extend({ + node: this, + typeInfo: this.type ? this.tree.types[this.type] : {}, + }, extra)); + } + /** + * Append (or insert) a list of child nodes. + * + * Tip: pass `{ before: 0 }` to prepend new nodes as first children. + * + * @returns first child added + */ + addChildren(nodeData, options) { + const tree = this.tree; + let { before = null, applyMinExpanLevel = true, _level } = options !== null && options !== void 0 ? options : {}; + // let { before, loadLazy=true, _level } = options ?? {}; + // const isTopCall = _level == null; + _level !== null && _level !== void 0 ? _level : (_level = this.getLevel()); + const nodeList = []; + try { + tree.enableUpdate(false); + if (isPlainObject(nodeData)) { + nodeData = [nodeData]; + } + const forceExpand = applyMinExpanLevel && _level < tree.options.minExpandLevel; + for (const child of nodeData) { + const subChildren = child.children; + delete child.children; + const n = new WunderbaumNode(tree, this, child); + if (forceExpand && !n.isUnloaded()) { + n.expanded = true; + } + nodeList.push(n); + if (subChildren) { + n.addChildren(subChildren, { _level: _level + 1 }); + } + } + if (!this.children) { + this.children = nodeList; + } + else if (before == null || this.children.length === 0) { + this.children = this.children.concat(nodeList); + } + else { + // Returns null if before is not a direct child: + before = this.findDirectChild(before); + const pos = this.children.indexOf(before); + assert(pos >= 0, `options.before must be a direct child of ${this}`); + // insert nodeList after children[pos] + this.children.splice(pos, 0, ...nodeList); + } + // this.triggerModifyChild("add", nodeList.length === 1 ? nodeList[0] : null); + tree.update(ChangeType.structure); + } + finally { + // if (tree.options.selectMode === "hier") { + // if (this.parent && this.parent.children) { + // this.fixSelection3FromEndNodes(); + // } else { + // // may happen when loading __root__; + // } + // } + tree.enableUpdate(true); + } + // if(isTopCall && loadLazy){ + // this.logWarn("addChildren(): loadLazy is not yet implemented.") + // } + return nodeList[0]; + } + /** + * Append or prepend a node, or append a child node. + * + * This a convenience function that calls addChildren() + * + * @param nodeData node definition + * @param [mode=child] 'before', 'after', 'firstChild', or 'child' ('over' is a synonym for 'child') + * @returns new node + */ + addNode(nodeData, mode = "appendChild") { + if (mode === "over") { + mode = "appendChild"; // compatible with drop region + } + switch (mode) { + case "after": + return this.parent.addChildren(nodeData, { + before: this.getNextSibling(), + }); + case "before": + return this.parent.addChildren(nodeData, { before: this }); + case "prependChild": + // Insert before the first child if any + // let insertBefore = this.children ? this.children[0] : undefined; + return this.addChildren(nodeData, { before: 0 }); + case "appendChild": + return this.addChildren(nodeData); + } + assert(false, `Invalid mode: ${mode}`); + return undefined; + } + /** + * Apply a modification (or navigation) operation. + * + * @see {@link Wunderbaum.applyCommand} + */ + applyCommand(cmd, options) { + return this.tree.applyCommand(cmd, this, options); + } + /** + * Collapse all expanded sibling nodes if any. + * (Automatically called when `autoCollapse` is true.) + */ + collapseSiblings(options) { + for (const node of this.parent.children) { + if (node !== this && node.expanded) { + node.setExpanded(false, options); + } + } + } + /** + * Add/remove one or more classes to `
    `. + * + * This also maintains `node.classes`, so the class will survive a re-render. + * + * @param className one or more class names. Multiple classes can be passed + * as space-separated string, array of strings, or set of strings. + */ + setClass(className, flag = true) { + const cnSet = toSet(className); + if (flag) { + if (this.classes === null) { + this.classes = new Set(); + } + cnSet.forEach((cn) => { + var _a; + this.classes.add(cn); + (_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.classList.toggle(cn, flag); + }); + } + else { + if (this.classes === null) { + return; + } + cnSet.forEach((cn) => { + var _a; + this.classes.delete(cn); + (_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.classList.toggle(cn, flag); + }); + if (this.classes.size === 0) { + this.classes = null; + } + } + } + /** Start editing this node's title. */ + startEditTitle() { + this.tree._callMethod("edit.startEditTitle", this); + } + /** Call `setExpanded()` on all descendant nodes. */ + async expandAll(flag = true, options) { + const tree = this.tree; + const minExpandLevel = this.tree.options.minExpandLevel; + const { depth = 99, loadLazy, force, keepActiveNodeVisible = true, } = options !== null && options !== void 0 ? options : {}; + const expandOpts = { + scrollIntoView: false, + force: force, + loadLazy: loadLazy, + }; + // this.logInfo(`expandAll(${flag})`); + // Expand all direct children in parallel: + async function _iter(n, level) { + var _a; + // n.logInfo(` _iter(${level})`); + if (level === 0) { + return; + } + // if (!flag && minExpandLevel && !force && n.getLevel() <= minExpandLevel) { + // return; // Do not collapse until minExpandLevel + // } + const level_1 = level == null ? null : level - 1; + const promises = []; + (_a = n.children) === null || _a === void 0 ? void 0 : _a.forEach((cn) => { + if (flag) { + if (!cn.expanded && (cn.children || (loadLazy && cn.lazy))) { + // Node is collapsed and may be expanded (i.e. has children or is lazy) + // Expanding may be async, so we store the promise. + // Also the recursion is delayed until expansion finished. + const p = cn.setExpanded(true, expandOpts); + promises.push(p); + p.then(async () => { + await _iter(cn, level_1); + }); + } + else { + // We don't expand the node, but still visit descendants. + // There we may find lazy nodes, so we + promises.push(_iter(cn, level_1)); + } + } + else { + // Collapsing is always synchronous, so no promises required + if (!minExpandLevel || force || cn.getLevel() > minExpandLevel) { + // Do not collapse until minExpandLevel + cn.setExpanded(false, expandOpts); + } + _iter(cn, level_1); // recursion, even if cn was already collapsed + } + }); + return new Promise((resolve) => { + Promise.all(promises).then(() => { + resolve(true); + }); + }); + } + const tag = tree.logTime(`${this}.expandAll(${flag})`); + try { + tree.enableUpdate(false); + await _iter(this, depth); + } + finally { + tree.enableUpdate(true); + tree.logTimeEnd(tag); + } + if (tree.activeNode && keepActiveNodeVisible) { + tree.activeNode.scrollIntoView(); + } + } + /** + * Find all descendant nodes that match condition (excluding self). + * + * If `match` is a string, search for exact node title. + * If `match` is a RegExp expression, apply it to node.title, using + * [RegExp.test()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test). + * If `match` is a callback, match all nodes for that the callback(node) returns true. + * + * Returns an empty array if no nodes were found. + * + * Examples: + * ```js + * // Match all node titles that match exactly 'Joe': + * nodeList = node.findAll("Joe") + * // Match all node titles that start with 'Joe' case sensitive: + * nodeList = node.findAll(/^Joe/) + * // Match all node titles that contain 'oe', case insensitive: + * nodeList = node.findAll(/oe/i) + * // Match all nodes with `data.price` >= 99: + * nodeList = node.findAll((n) => { + * return n.data.price >= 99; + * }) + * ``` + */ + findAll(match) { + const matcher = typeof match === "function" ? match : makeNodeTitleMatcher(match); + const res = []; + this.visit((n) => { + if (matcher(n)) { + res.push(n); + } + }); + return res; + } + /** Return the direct child with a given key, index or null. */ + findDirectChild(ptr) { + const cl = this.children; + if (!cl) { + return null; + } + if (typeof ptr === "string") { + for (let i = 0, l = cl.length; i < l; i++) { + if (cl[i].key === ptr) { + return cl[i]; + } + } + } + else if (typeof ptr === "number") { + return cl[ptr]; + } + else if (ptr.parent === this) { + // Return null if `ptr` is not a direct child + return ptr; + } + return null; + } + /** + * Find first descendant node that matches condition (excluding self) or null. + * + * @see {@link WunderbaumNode.findAll} for examples. + */ + findFirst(match) { + const matcher = typeof match === "function" ? match : makeNodeTitleMatcher(match); + let res = null; + this.visit((n) => { + if (matcher(n)) { + res = n; + return false; + } + }); + return res; + } + /** Find a node relative to self. + * + * @see {@link Wunderbaum.findRelatedNode|tree.findRelatedNode()} + */ + findRelatedNode(where, includeHidden = false) { + return this.tree.findRelatedNode(this, where, includeHidden); + } + /** + * Iterator version of {@link WunderbaumNode.format}. + */ + *format_iter(name_cb, connectors) { + connectors !== null && connectors !== void 0 ? connectors : (connectors = [" ", " | ", " ╰─ ", " ├─ "]); + name_cb !== null && name_cb !== void 0 ? name_cb : (name_cb = (node) => "" + node); + function _is_last(node) { + const ca = node.parent.children; + return node === ca[ca.length - 1]; + } + const _format_line = (node) => { + // https://www.measurethat.net/Benchmarks/Show/12196/0/arr-unshift-vs-push-reverse-small-array + const parts = [name_cb(node)]; + parts.unshift(connectors[_is_last(node) ? 2 : 3]); + let p = node.parent; + while (p && p !== this) { + // `this` is the top node + parts.unshift(connectors[_is_last(p) ? 0 : 1]); + p = p.parent; + } + return parts.join(""); + }; + yield name_cb(this); + for (const node of this) { + yield _format_line(node); + } + } + /** + * Return a multiline string representation of a node/subnode hierarchy. + * Mostly useful for debugging. + * + * Example: + * ```js + * console.info(tree.getActiveNode().format((n)=>n.title)); + * ``` + * logs + * ``` + * Books + * ├─ Art of War + * ╰─ Don Quixote + * ``` + * @see {@link WunderbaumNode.format_iter} + */ + format(name_cb, connectors) { + const a = []; + for (const line of this.format_iter(name_cb, connectors)) { + a.push(line); + } + return a.join("\n"); + } + /** Return the `` element with a given index or id. + * @returns {WunderbaumNode | null} + */ + getColElem(colIdx) { + var _a; + if (typeof colIdx === "string") { + colIdx = this.tree.columns.findIndex((value) => value.id === colIdx); + } + const colElems = (_a = this._rowElem) === null || _a === void 0 ? void 0 : _a.querySelectorAll("span.wb-col"); + return colElems ? colElems[colIdx] : null; + } + /** + * Return all nodes with the same refKey. + * + * @param includeSelf Include this node itself. + * @see {@link Wunderbaum.findByRefKey} + */ + getCloneList(includeSelf = false) { + if (!this.refKey) { + return []; + } + const clones = this.tree.findByRefKey(this.refKey); + if (includeSelf) { + return clones; + } + return [...clones].filter((n) => n !== this); + } + /** Return the first child node or null. + * @returns {WunderbaumNode | null} + */ + getFirstChild() { + return this.children ? this.children[0] : null; + } + /** Return the last child node or null. + * @returns {WunderbaumNode | null} + */ + getLastChild() { + return this.children ? this.children[this.children.length - 1] : null; + } + /** Return node depth (starting with 1 for top level nodes). */ + getLevel() { + let i = 0, p = this.parent; + while (p) { + i++; + p = p.parent; + } + return i; + } + /** Return the successive node (under the same parent) or null. */ + getNextSibling() { + const ac = this.parent.children; + const idx = ac.indexOf(this); + return ac[idx + 1] || null; + } + /** Return the parent node (null for the system root node). */ + getParent() { + // TODO: return null for top-level nodes? + return this.parent; + } + /** Return an array of all parent nodes (top-down). + * @param includeRoot Include the invisible system root node. + * @param includeSelf Include the node itself. + */ + getParentList(includeRoot = false, includeSelf = false) { + const l = []; + let dtn = includeSelf ? this : this.parent; + while (dtn) { + if (includeRoot || dtn.parent) { + l.unshift(dtn); + } + dtn = dtn.parent; + } + return l; + } + /** Return a string representing the hierachical node path, e.g. "a/b/c". + * @param includeSelf + * @param node property name or callback + * @param separator + */ + getPath(includeSelf = true, part = "title", separator = "/") { + // includeSelf = includeSelf !== false; + // part = part || "title"; + // separator = separator || "/"; + let val; + const path = []; + const isFunc = typeof part === "function"; + this.visitParents((n) => { + if (n.parent) { + val = isFunc + ? part(n) + : n[part]; + path.unshift(val); + } + return undefined; // TODO remove this line + }, includeSelf); + return path.join(separator); + } + /** Return the preceeding node (under the same parent) or null. */ + getPrevSibling() { + const ac = this.parent.children; + const idx = ac.indexOf(this); + return ac[idx - 1] || null; + } + /** Return true if node has children. + * Return undefined if not sure, i.e. the node is lazy and not yet loaded. + */ + hasChildren() { + if (this.lazy) { + if (this.children == null) { + return undefined; // null or undefined: Not yet loaded + } + else if (this.children.length === 0) { + return false; // Loaded, but response was empty + } + else if (this.children.length === 1 && + this.children[0].isStatusNode()) { + return undefined; // Currently loading or load error + } + return true; // One or more child nodes + } + return !!(this.children && this.children.length); + } + /** Return true if node has className set. */ + hasClass(className) { + return this.classes ? this.classes.has(className) : false; + } + /** Return true if this node is the currently active tree node. */ + isActive() { + return this.tree.activeNode === this; + } + /** Return true if this node is a direct or indirect parent of `other`. + * @see {@link WunderbaumNode.isParentOf} + */ + isAncestorOf(other) { + return other && other.isDescendantOf(this); + } + /** Return true if this node is a **direct** subnode of `other`. + * @see {@link WunderbaumNode.isDescendantOf} + */ + isChildOf(other) { + return other && this.parent === other; + } + /** Return true if this node's refKey is used by at least one other node. + */ + isClone() { + return !!this.refKey && this.tree.findByRefKey(this.refKey).length > 1; + } + /** Return true if this node's title spans all columns, i.e. the node has no + * grid cells. + */ + isColspan() { + return !!this.getOption("colspan"); + } + /** Return true if this node is a direct or indirect subnode of `other`. + * @see {@link WunderbaumNode.isChildOf} + */ + isDescendantOf(other) { + if (!other || other.tree !== this.tree) { + return false; + } + let p = this.parent; + while (p) { + if (p === other) { + return true; + } + if (p === p.parent) { + error(`Recursive parent link: ${p}`); + } + p = p.parent; + } + return false; + } + /** Return true if this node has children, i.e. the node is generally expandable. + * If `andCollapsed` is set, we also check if this node is collapsed, i.e. + * an expand operation is currently possible. + */ + isExpandable(andCollapsed = false) { + // `false` is never expandable (unoffical) + if ((andCollapsed && this.expanded) || this.children === false) { + return false; + } + if (this.children == null) { + return !!this.lazy; // null or undefined can trigger lazy load + } + if (this.children.length === 0) { + return !!this.tree.options.emptyChildListExpandable; + } + return true; + } + /** Return true if _this_ node is currently in edit-title mode. + * + * See {@link Wunderbaum.startEditTitle} to check if any node is currently edited. + */ + isEditingTitle() { + return this.tree._callMethod("edit.isEditingTitle", this); + } + /** Return true if this node is currently expanded. */ + isExpanded() { + return !!this.expanded; + } + /** Return true if this node is the first node of its parent's children. */ + isFirstSibling() { + const p = this.parent; + return !p || p.children[0] === this; + } + /** Return true if this node is the last node of its parent's children. */ + isLastSibling() { + const p = this.parent; + return !p || p.children[p.children.length - 1] === this; + } + /** Return true if this node is lazy (even if data was already loaded) */ + isLazy() { + return !!this.lazy; + } + /** Return true if node is lazy and loaded. For non-lazy nodes always return true. */ + isLoaded() { + return !this.lazy || this.hasChildren() !== undefined; // Also checks if the only child is a status node + } + /** Return true if node is currently loading, i.e. a GET request is pending. */ + isLoading() { + return this._isLoading; + } + /** Return true if this node is a temporarily generated status node of type 'paging'. */ + isPagingNode() { + return this.statusNodeType === "paging"; + } + /** Return true if this node is a **direct** parent of `other`. + * @see {@link WunderbaumNode.isAncestorOf} + */ + isParentOf(other) { + return other && other.parent === this; + } + /** (experimental) Return true if this node is partially loaded. */ + isPartload() { + return !!this._partload; + } + /** Return true if this node is partially selected (tri-state). */ + isPartsel() { + return !this.selected && !!this._partsel; + } + /** Return true if this node has DOM representaion, i.e. is displayed in the viewport. */ + isRadio() { + return !!this.parent.radiogroup || this.getOption("checkbox") === "radio"; + } + /** Return true if this node has DOM representaion, i.e. is displayed in the viewport. */ + isRendered() { + return !!this._rowElem; + } + /** Return true if this node is the (invisible) system root node. + * @see {@link WunderbaumNode.isTopLevel} + */ + isRootNode() { + return this.tree.root === this; + } + /** Return true if this node is selected, i.e. the checkbox is set. + * `undefined` if partly selected (tri-state), false otherwise. + */ + isSelected() { + return this.selected ? true : this._partsel ? undefined : false; + } + /** Return true if this node is a temporarily generated system node like + * 'loading', 'paging', or 'error' (node.statusNodeType contains the type). + */ + isStatusNode() { + return !!this.statusNodeType; + } + /** Return true if this a top level node, i.e. a direct child of the (invisible) system root node. */ + isTopLevel() { + return this.tree.root === this.parent; + } + /** Return true if node is marked lazy but not yet loaded. + * For non-lazy nodes always return false. + */ + isUnloaded() { + // Also checks if the only child is a status node: + return this.hasChildren() === undefined; + } + /** Return true if all parent nodes are expanded. Note: this does not check + * whether the node is scrolled into the visible part of the screen or viewport. + */ + isVisible() { + const hasFilter = this.tree.filterMode === "hide"; + const parents = this.getParentList(false, false); + // TODO: check $(n.span).is(":visible") + // i.e. return false for nodes (but not parents) that are hidden + // by a filter + if (hasFilter && !this.match && !this.subMatchCount) { + // this.debug( "isVisible: HIDDEN (" + hasFilter + ", " + this.match + ", " + this.match + ")" ); + return false; + } + for (let i = 0, l = parents.length; i < l; i++) { + const n = parents[i]; + if (!n.expanded) { + // this.debug("isVisible: HIDDEN (parent collapsed)"); + return false; + } + // if (hasFilter && !n.match && !n.subMatchCount) { + // this.debug("isVisible: HIDDEN (" + hasFilter + ", " + this.match + ", " + this.match + ")"); + // return false; + // } + } + // this.debug("isVisible: VISIBLE"); + return true; + } + _loadSourceObject(source, level) { + var _a; + const tree = this.tree; + level !== null && level !== void 0 ? level : (level = this.getLevel()); + // Let caller modify the parsed JSON response: + const res = this._callEvent("receive", { response: source }); + if (res != null) { + source = res; + } + if (isArray(source)) { + source = { children: source }; + } + assert(isPlainObject(source), `Expected an array or plain object: ${source}`); + const format = (_a = source.format) !== null && _a !== void 0 ? _a : "nested"; + assert(format === "nested" || format === "flat", `Expected source.format = 'nested' or 'flat': ${format}`); + // Pre-rocess for 'nested' or 'flat' format + decompressSourceData(source); + assert(source.children, "If `source` is an object, it must have a `children` property"); + if (source.types) { + tree.logInfo("Redefine types", source.columns); + tree.setTypes(source.types, false); + delete source.types; + } + if (source.columns) { + tree.logInfo("Redefine columns", source.columns); + tree.columns = source.columns; + delete source.columns; + tree.update(ChangeType.colStructure); + } + this.addChildren(source.children); + // Add extra data to `tree.data` + for (const [key, value] of Object.entries(source)) { + if (!RESERVED_TREE_SOURCE_KEYS.has(key)) { + tree.data[key] = value; + // tree.logDebug(`Add source.${key} to tree.data.${key}`); + } + } + if (tree.options.selectMode === "hier") { + this.fixSelection3FromEndNodes(); + } + this._callEvent("load"); + } + async _fetchWithOptions(source) { + var _a, _b; + // Either a URL string or an object with a `.url` property. + let url, params, body, options, rest; + let fetchOpts = {}; + if (typeof source === "string") { + // source is a plain URL string: assume GET request + url = source; + fetchOpts.method = "GET"; + } + else if (isPlainObject(source)) { + // source is a plain object with `.url` property. + ({ url, params, body, options, ...rest } = source); + assert(!rest || Object.keys(rest).length === 0, `Unexpected source properties: ${Object.keys(rest)}. Use 'options' instead.`); + assert(typeof url === "string", `expected source.url as string`); + if (isPlainObject(options)) { + fetchOpts = options; + } + if (isPlainObject(body)) { + // we also accept 'body' as object... + assert(!fetchOpts.body, "options.body should be passed as source.body"); + fetchOpts.body = JSON.stringify(fetchOpts.body); + (_a = fetchOpts.method) !== null && _a !== void 0 ? _a : (fetchOpts.method = "POST"); // set default + } + if (isPlainObject(params)) { + url += "?" + new URLSearchParams(params); + (_b = fetchOpts.method) !== null && _b !== void 0 ? _b : (fetchOpts.method = "GET"); // set default + } + } + else { + url = ""; // keep linter happy + error(`Unsupported source format: ${source}`); + } + this.setStatus(NodeStatusType.loading); + const response = await fetch(url, fetchOpts); + if (!response.ok) { + error(`GET ${url} returned ${response.status}, ${response}`); + } + return await response.json(); + } + /** Download data from the cloud, then call `.update()`. */ + async load(source) { + const tree = this.tree; + const requestId = Date.now(); + const prevParent = this.parent; + const start = Date.now(); + let elap = 0, elapLoad = 0, elapProcess = 0; + // Check for overlapping requests + if (this._requestId) { + this.logWarn(`Recursive load request #${requestId} while #${this._requestId} is pending.`); + // node.debug("Send load request #" + requestId); + } + this._requestId = requestId; + // const timerLabel = tree.logTime(this + ".load()"); + try { + const url = typeof source === "string" ? source : source.url; + if (!url) { + // An array or a plain object (that does NOT contain a `.url` property) + // will be treated as native Wunderbaum data + if (typeof source.then === "function") { + const msg = tree.logTime(`Resolve thenable ${source}`); + source = await Promise.resolve(source); + tree.logTimeEnd(msg); + } + this._loadSourceObject(source); + elapProcess = Date.now() - start; + } + else { + // Either a URL string or an object with a `.url` property. + const data = await this._fetchWithOptions(source); + elapLoad = Date.now() - start; + if (this._requestId && this._requestId > requestId) { + this.logWarn(`Ignored load response #${requestId} because #${this._requestId} is pending.`); + return; + } + else { + this.logDebug(`Received response for load request #${requestId}`); + } + if (this.parent === null && prevParent !== null) { + this.logWarn("Lazy parent node was removed while loading: discarding response."); + return; + } + this.setStatus(NodeStatusType.ok); + // if (data.columns) { + // tree.logInfo("Re-define columns", data.columns); + // util.assert(!this.parent); + // tree.columns = data.columns; + // delete data.columns; + // tree.updateColumns({ calculateCols: false }); + // } + const startProcess = Date.now(); + this._loadSourceObject(data); + elapProcess = Date.now() - startProcess; + } + } + catch (error) { + this.logError("Error during load()", source, error); + this._callEvent("error", { error: error }); + this.setStatus(NodeStatusType.error, { message: "" + error }); + throw error; + } + finally { + this._requestId = 0; + elap = Date.now() - start; + if (tree.options.debugLevel >= 3) { + tree.logInfo(`Load source took ${elap / 1000} seconds ` + + `(transfer: ${elapLoad / 1000}s, ` + + `processing: ${elapProcess / 1000}s)`); + } + } + } + /** + * Load content of a lazy node. + * If the node is already loaded, nothing happens. + * @param [forceReload=false] If true, reload even if already loaded. + */ + async loadLazy(forceReload = false) { + const wasExpanded = this.expanded; + assert(this.lazy, "load() requires a lazy node"); + if (!forceReload && !this.isUnloaded()) { + return; // Already loaded: nothing to do + } + if (this.isLoading()) { + this.logWarn("loadLazy() called while already loading: ignored."); + return; // Already loading: prevent duplicate requests + } + if (this.isLoaded()) { + this.resetLazy(); // Also collapses if currently expanded + } + // `lazyLoad` may be long-running, so mark node as loading now. `this.load()` + // will reset the status later. + this.setStatus(NodeStatusType.loading); + try { + const source = await this._callEvent("lazyLoad"); + if (source === false) { + this.setStatus(NodeStatusType.ok); + return; + } + assert(isArray(source) || (source && source.url), "The lazyLoad event must return a node list, `{url: ...}`, or false."); + await this.load(source); + this.setStatus(NodeStatusType.ok); // Also resets `this._isLoading` + if (wasExpanded) { + this.expanded = true; + this.tree.update(ChangeType.structure); + } + else { + this.update(); // Fix expander icon to 'loaded' + } + } + catch (e) { + this.logError("Error during loadLazy()", e); + this._callEvent("error", { error: e }); + // Also resets `this._isLoading`: + this.setStatus(NodeStatusType.error, { message: "" + e }); + } + return; + } + /** Write to `console.log` with node name as prefix if opts.debugLevel >= 4. + * @see {@link WunderbaumNode.logDebug} + */ + log(...args) { + if (this.tree.options.debugLevel >= 4) { + console.log(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Write to `console.debug` with node name as prefix if opts.debugLevel >= 4 + * and browser console level includes debug/verbose messages. + * @see {@link WunderbaumNode.log} + */ + logDebug(...args) { + if (this.tree.options.debugLevel >= 4) { + console.debug(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Write to `console.error` with node name as prefix if opts.debugLevel >= 1. */ + logError(...args) { + if (this.tree.options.debugLevel >= 1) { + console.error(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Write to `console.info` with node name as prefix if opts.debugLevel >= 3. */ + logInfo(...args) { + if (this.tree.options.debugLevel >= 3) { + console.info(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Write to `console.warn` with node name as prefix if opts.debugLevel >= 2. */ + logWarn(...args) { + if (this.tree.options.debugLevel >= 2) { + console.warn(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Expand all parents and optionally scroll into visible area as neccessary. + * Promise is resolved, when lazy loading and animations are done. + * @param {object} [options] passed to `setExpanded()`. + * Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true} + */ + async makeVisible(options) { + let i; + const dfd = new Deferred(); + const deferreds = []; + const parents = this.getParentList(false, false); + const len = parents.length; + const noAnimation = getOption(options, "noAnimation", false); + const scroll = getOption(options, "scrollIntoView", true); + // Expand bottom-up, so only the top node is animated + for (i = len - 1; i >= 0; i--) { + // self.debug("pushexpand" + parents[i]); + const seOpts = { noAnimation: noAnimation }; + deferreds.push(parents[i].setExpanded(true, seOpts)); + } + Promise.all(deferreds).then(() => { + // All expands have finished + // self.debug("expand DONE", scroll); + // Note: this.tree may be none when switching demo trees + if (scroll && this.tree) { + // Make sure markup and _rowIdx is updated before we do the scroll calculations + this.tree.updatePendingModifications(); + this.scrollIntoView().then(() => { + // self.debug("scroll DONE"); + dfd.resolve(); + }); + } + else { + dfd.resolve(); + } + }); + return dfd.promise(); + } + /** Move this node to targetNode. */ + moveTo(targetNode, mode = "appendChild", map) { + if (mode === "over") { + mode = "appendChild"; // compatible with drop region + } + if (mode === "prependChild") { + if (targetNode.children && targetNode.children.length) { + mode = "before"; + targetNode = targetNode.children[0]; + } + else { + mode = "appendChild"; + } + } + let pos; + const tree = this.tree; + const prevParent = this.parent; + const targetParent = mode === "appendChild" ? targetNode : targetNode.parent; + if (this === targetNode) { + return; + } + else if (!this.parent) { + error("Cannot move system root"); + } + else if (targetParent.isDescendantOf(this)) { + error("Cannot move a node to its own descendant"); + } + if (targetParent !== prevParent) { + prevParent.triggerModifyChild("remove", this); + } + // Unlink this node from current parent + if (this.parent.children.length === 1) { + if (this.parent === targetParent) { + return; // #258 + } + this.parent.children = this.parent.lazy ? [] : null; + this.parent.expanded = false; + } + else { + pos = this.parent.children.indexOf(this); + assert(pos >= 0, "invalid source parent"); + this.parent.children.splice(pos, 1); + } + // Insert this node to target parent's child list + this.parent = targetParent; + if (targetParent.hasChildren()) { + switch (mode) { + case "appendChild": + // Append to existing target children + targetParent.children.push(this); + break; + case "before": + // Insert this node before target node + pos = targetParent.children.indexOf(targetNode); + assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos, 0, this); + break; + case "after": + // Insert this node after target node + pos = targetParent.children.indexOf(targetNode); + assert(pos >= 0, "invalid target parent"); + targetParent.children.splice(pos + 1, 0, this); + break; + default: + error(`Invalid mode '${mode}'.`); + } + } + else { + targetParent.children = [this]; + } + // Let caller modify the nodes + if (map) { + targetNode.visit(map, true); + } + if (targetParent === prevParent) { + targetParent.triggerModifyChild("move", this); + } + else { + // prevParent.triggerModifyChild("remove", this); + targetParent.triggerModifyChild("add", this); + } + // Handle cross-tree moves + if (tree !== targetNode.tree) { + // Fix node.tree for all source nodes + // util.assert(false, "Cross-tree move is not yet implemented."); + this.logWarn("Cross-tree moveTo is experimental!"); + this.visit((n) => { + // TODO: fix selection state and activation, ... + n.tree = targetNode.tree; + }, true); + } + // Make sure we update async, because discarding the markup would prevent + // DragAndDrop to generate a dragend event on the source node + setTimeout(() => { + // Even indentation may have changed: + tree.update(ChangeType.any); + }, 0); + // TODO: fix selection state + // TODO: fix active state + } + /** Set focus relative to this node and optionally activate. + * + * 'left' collapses the node if it is expanded, or move to the parent + * otherwise. + * 'right' expands the node if it is collapsed, or move to the first + * child otherwise. + * + * @param where 'down', 'first', 'last', 'left', 'parent', 'right', or 'up'. + * (Alternatively the `event.key` that would normally trigger this move, + * e.g. `ArrowLeft` = 'left'. + * @param options + */ + async navigate(where, options) { + // Allow to pass 'ArrowLeft' instead of 'left' + where = KEY_TO_ACTION_DICT[where] || where; + // Otherwise activate or focus the related node + const node = this.findRelatedNode(where); + if (!node) { + this.logWarn(`Could not find related node '${where}'.`); + return Promise.resolve(this); + } + // setFocus/setActive will scroll later (if autoScroll is specified) + try { + node.makeVisible({ scrollIntoView: false }); + } + catch (e) { + // ignore + } + node.setFocus(); + if ((options === null || options === void 0 ? void 0 : options.activate) === false) { + return Promise.resolve(this); + } + return node.setActive(true, { event: options === null || options === void 0 ? void 0 : options.event }); + } + /** Delete this node and all descendants. */ + remove() { + const tree = this.tree; + const pos = this.parent.children.indexOf(this); + this.triggerModify("remove"); + this.parent.children.splice(pos, 1); + this.visit((n) => { + n.removeMarkup(); + tree._unregisterNode(n); + }, true); + tree.update(ChangeType.structure); + } + /** Remove all descendants of this node. */ + removeChildren() { + var _a, _b; + const tree = this.tree; + if (!this.children) { + return; + } + if ((_a = tree.activeNode) === null || _a === void 0 ? void 0 : _a.isDescendantOf(this)) { + tree.activeNode.setActive(false); // TODO: don't fire events + } + if ((_b = tree.focusNode) === null || _b === void 0 ? void 0 : _b.isDescendantOf(this)) { + tree._setFocusNode(null); + } + // TODO: persist must take care to clear select and expand cookies + // Unlink children to support GC + // TODO: also delete this.children (not possible using visit()) + this.triggerModifyChild("remove", null); + this.visit((n) => { + tree._unregisterNode(n); + }); + if (this.lazy) { + // 'undefined' would be interpreted as 'not yet loaded' for lazy nodes + this.children = []; + } + else { + this.children = null; + } + // util.assert(this.parent); // don't call this for root node + if (!this.isRootNode()) { + this.expanded = false; + } + this.tree.update(ChangeType.structure); + } + /** Remove all HTML markup from the DOM. */ + removeMarkup() { + if (this._rowElem) { + delete this._rowElem._wb_node; + this._rowElem.remove(); + this._rowElem = undefined; + } + } + _getRenderInfo() { + const allColInfosById = {}; + const renderColInfosById = {}; + const isColspan = this.isColspan(); + const colElems = this._rowElem + ? (this._rowElem.querySelectorAll("span.wb-col")) + : null; + let idx = 0; + for (const col of this.tree.columns) { + allColInfosById[col.id] = { + id: col.id, + idx: idx, + elem: colElems ? colElems[idx] : null, + info: col, + }; + // renderColInfosById only contains columns that need rendering: + if (!isColspan && col.id !== "*") { + renderColInfosById[col.id] = allColInfosById[col.id]; + } + idx++; + } + return { + allColInfosById: allColInfosById, + renderColInfosById: renderColInfosById, + }; + } + _createIcon(iconMap, parentElem, replaceChild, showLoading) { + let iconSpan; + let icon = this.getOption("icon"); + if (this._errorInfo) { + icon = iconMap.error; + } + else if (this._isLoading && showLoading) { + // Status nodes, or nodes without expander (< minExpandLevel) should + // display the 'loading' status with the i.wb-icon span + icon = iconMap.loading; + } + if (icon === false) { + return null; // explicitly disabled: don't try default icons + } + if (typeof icon === "string") ; + else if (this.statusNodeType) { + icon = iconMap[this.statusNodeType]; + } + else if (this.expanded) { + icon = iconMap.folderOpen; + } + else if (this.children) { + icon = iconMap.folder; + } + else if (this.lazy) { + icon = iconMap.folderLazy; + } + else { + icon = iconMap.doc; + } + // this.log("_createIcon: " + icon); + if (!icon) { + iconSpan = document.createElement("i"); + iconSpan.className = "wb-icon"; + } + else if (icon.indexOf("<") >= 0) { + // HTML + iconSpan = elemFromHtml(icon); + } + else if (TEST_IMG.test(icon)) { + // Image URL + iconSpan = elemFromHtml(``); + } + else { + // Class name + iconSpan = document.createElement("i"); + iconSpan.className = "wb-icon " + icon; + } + if (replaceChild) { + parentElem.replaceChild(iconSpan, replaceChild); + } + else { + parentElem.appendChild(iconSpan); + } + // Event handler `tree.iconBadge` can return a badge text or HTMLSpanElement + const cbRes = this._callEvent("iconBadge", { iconSpan: iconSpan }); + let badge = null; + if (cbRes != null && cbRes !== false) { + let classes = ""; + let tooltip = ""; + if (isPlainObject(cbRes)) { + badge = "" + cbRes.badge; + classes = cbRes.badgeClass ? " " + cbRes.badgeClass : ""; + tooltip = cbRes.badgeTooltip ? ` title="${cbRes.badgeTooltip}"` : ""; + } + else if (typeof cbRes === "number") { + badge = "" + cbRes; + } + else { + badge = cbRes; // string or HTMLSpanElement + } + if (typeof badge === "string") { + badge = elemFromHtml(`${escapeHtml(badge)}`); + } + if (badge) { + iconSpan.append(badge); + } + } + // this.log("_createIcon: ", iconSpan); + return iconSpan; + } + /** + * Create a whole new `
    ` element. + * @see {@link WunderbaumNode._render} + */ + _render_markup(opts) { + const tree = this.tree; + const treeOptions = tree.options; + const checkbox = this.getOption("checkbox"); + const columns = tree.columns; + const level = this.getLevel(); + const activeColIdx = tree.isRowNav() ? null : tree.activeColIdx; + let elem; + let rowDiv = this._rowElem; + let checkboxSpan = null; + let expanderSpan = null; + const isNew = !rowDiv; + assert(isNew, "Expected unrendered node"); + assert(!isNew || (opts && opts.after), "opts.after expected, unless updating"); + assert(!this.isRootNode(), "Root node not allowed"); + rowDiv = document.createElement("div"); + rowDiv.classList.add("wb-row"); + rowDiv.style.top = this._rowIdx * ROW_HEIGHT + "px"; + this._rowElem = rowDiv; + // Attach a node reference to the DOM Element: + rowDiv._wb_node = this; + const nodeElem = document.createElement("span"); + nodeElem.classList.add("wb-node", "wb-col"); + rowDiv.appendChild(nodeElem); + let ofsTitlePx = 0; + if (checkbox) { + checkboxSpan = document.createElement("i"); + checkboxSpan.classList.add("wb-checkbox"); + if (checkbox === "radio" || this.parent.radiogroup) { + checkboxSpan.classList.add("wb-radio"); + } + nodeElem.appendChild(checkboxSpan); + ofsTitlePx += ICON_WIDTH; + } + for (let i = level - 1; i > 0; i--) { + elem = document.createElement("i"); + elem.classList.add("wb-indent"); + nodeElem.appendChild(elem); + ofsTitlePx += ICON_WIDTH; + } + if (!treeOptions.minExpandLevel || level > treeOptions.minExpandLevel) { + expanderSpan = document.createElement("i"); + expanderSpan.classList.add("wb-expander"); + nodeElem.appendChild(expanderSpan); + ofsTitlePx += ICON_WIDTH; + } + // Render the icon (show a 'loading' icon if we do not have an expander that + // we would prefer). + const iconSpan = this._createIcon(tree.iconMap, nodeElem, null, !expanderSpan); + if (iconSpan) { + ofsTitlePx += ICON_WIDTH; + } + const titleSpan = document.createElement("span"); + titleSpan.classList.add("wb-title"); + nodeElem.appendChild(titleSpan); + // this._callEvent("enhanceTitle", { titleSpan: titleSpan }); + // Store the width of leading icons with the node, so we can calculate + // the width of the embedded title span later + nodeElem._ofsTitlePx = ofsTitlePx; + // Support HTML5 drag-n-drop + if (tree.options.dnd.dragStart) { + nodeElem.draggable = true; + } + // Render columns + const isColspan = this.isColspan(); + if (!isColspan && columns.length > 1) { + let colIdx = 0; + for (const col of columns) { + colIdx++; + let colElem; + if (col.id === "*") { + colElem = nodeElem; + } + else { + colElem = document.createElement("span"); + colElem.classList.add("wb-col"); + rowDiv.appendChild(colElem); + } + if (colIdx === activeColIdx) { + colElem.classList.add("wb-active"); + } + // Add classes from `columns` definition to `` cells + col.classes ? colElem.classList.add(...col.classes.split(" ")) : 0; + colElem.style.left = col._ofsPx + "px"; + colElem.style.width = col._widthPx + "px"; + if (isNew && col.html) { + if (typeof col.html === "string") { + colElem.innerHTML = col.html; + } + } + } + } + // Attach to DOM as late as possible + const after = opts ? opts.after : "last"; + switch (after) { + case "first": + tree.nodeListElement.prepend(rowDiv); + break; + case "last": + tree.nodeListElement.appendChild(rowDiv); + break; + default: + opts.after.after(rowDiv); + } + // Now go on and fill in data and update classes + opts.isNew = true; + this._render_data(opts); + } + /** + * Render `node.title`, `.icon` into an existing row. + * + * @see {@link WunderbaumNode._render} + */ + _render_data(opts) { + assert(this._rowElem, "No _rowElem"); + const tree = this.tree; + const treeOptions = tree.options; + const rowDiv = this._rowElem; + const isNew = !!opts.isNew; // Called by _render_markup()? + const preventScroll = !!opts.preventScroll; + const columns = tree.columns; + const isColspan = this.isColspan(); + // Row markup already exists + const nodeElem = rowDiv.querySelector("span.wb-node"); + const titleSpan = nodeElem.querySelector("span.wb-title"); + const scrollTop = tree.element.scrollTop; + if (this.titleWithHighlight) { + titleSpan.innerHTML = this.titleWithHighlight; + } + else { + titleSpan.textContent = this.title; // TODO: this triggers scroll events + } + // NOTE: At least on Safari, this render call triggers a scroll event + // probably when a focused input is replaced. + if (preventScroll) { + tree.element.scrollTop = scrollTop; + } + // Set the width of the title span, so overflow ellipsis work + if (!treeOptions.skeleton) { + if (isColspan) { + const vpWidth = tree.element.clientWidth; + titleSpan.style.width = + vpWidth - nodeElem._ofsTitlePx - TITLE_SPAN_PAD_Y + "px"; + } + else { + titleSpan.style.width = + columns[0]._widthPx - + nodeElem._ofsTitlePx - + TITLE_SPAN_PAD_Y + + "px"; + } + } + // Update row classes + opts.isDataChange = true; + this._render_status(opts); + // Let user modify the result + if (this.statusNodeType) { + this._callEvent("renderStatusNode", { + isNew: isNew, + nodeElem: nodeElem, + isColspan: isColspan, + }); + } + else if (this.parent) { + // Skip root node + const renderInfo = this._getRenderInfo(); + this._callEvent("render", { + isNew: isNew, + nodeElem: nodeElem, + isColspan: isColspan, + allColInfosById: renderInfo.allColInfosById, + renderColInfosById: renderInfo.renderColInfosById, + }); + } + } + /** + * Update row classes to reflect active, focuses, etc. + * @see {@link WunderbaumNode._render} + */ + _render_status(opts) { + // this.log("_render_status", opts); + const tree = this.tree; + const iconMap = tree.iconMap; + const treeOptions = tree.options; + const typeInfo = this.type ? tree.types[this.type] : null; + const rowDiv = this._rowElem; + // Row markup already exists + const nodeElem = rowDiv.querySelector("span.wb-node"); + const expanderSpan = nodeElem.querySelector("i.wb-expander"); + const checkboxSpan = nodeElem.querySelector("i.wb-checkbox"); + const rowClasses = ["wb-row"]; + this.expanded ? rowClasses.push("wb-expanded") : 0; + this.lazy ? rowClasses.push("wb-lazy") : 0; + this.selected ? rowClasses.push("wb-selected") : 0; + this._partsel ? rowClasses.push("wb-partsel") : 0; + this === tree.activeNode ? rowClasses.push("wb-active") : 0; + this === tree.focusNode ? rowClasses.push("wb-focus") : 0; + this._errorInfo ? rowClasses.push("wb-error") : 0; + this._isLoading ? rowClasses.push("wb-loading") : 0; + this.isColspan() ? rowClasses.push("wb-colspan") : 0; + this.statusNodeType + ? rowClasses.push("wb-status-" + this.statusNodeType) + : 0; + this.match ? rowClasses.push("wb-match") : 0; + this.subMatchCount ? rowClasses.push("wb-submatch") : 0; + treeOptions.skeleton ? rowClasses.push("wb-skeleton") : 0; + // Replace previous classes: + rowDiv.className = rowClasses.join(" "); + // Add classes from `node.classes` + this.classes ? rowDiv.classList.add(...this.classes) : 0; + // Add classes from `tree.types[node.type]` + if (typeInfo && typeInfo.classes) { + rowDiv.classList.add(...typeInfo.classes); + } + if (expanderSpan) { + let image = null; + if (this._isLoading) { + image = iconMap.loading; + } + else if (this.isExpandable(false)) { + if (this.expanded) { + image = iconMap.expanderExpanded; + } + else { + image = iconMap.expanderCollapsed; + } + } + else if (this.lazy && this.children == null) { + image = iconMap.expanderLazy; + } + if (image == null) { + expanderSpan.classList.add("wb-indent"); + } + else if (TEST_IMG.test(image)) { + expanderSpan.style.backgroundImage = `url('${image}')`; + } + else { + expanderSpan.className = "wb-expander " + image; + } + } + if (checkboxSpan) { + let cbclass = "wb-checkbox "; + if (this.isRadio()) { + cbclass += "wb-radio "; + if (this.selected) { + cbclass += iconMap.radioChecked; + // } else if (this._partsel) { + // cbclass += iconMap.radioUnknown; + } + else { + cbclass += iconMap.radioUnchecked; + } + } + else { + if (this.selected) { + cbclass += iconMap.checkChecked; + } + else if (this._partsel) { + cbclass += iconMap.checkUnknown; + } + else { + cbclass += iconMap.checkUnchecked; + } + } + checkboxSpan.className = cbclass; + } + // Fix active cell in cell-nav mode + if (!opts.isNew) { + let i = 0; + for (const colSpan of rowDiv.children) { + colSpan.classList.toggle("wb-active", i++ === tree.activeColIdx); + colSpan.classList.remove("wb-error", "wb-invalid"); + } + // Update icon (if not opts.isNew, which would rebuild markup anyway) + const iconSpan = nodeElem.querySelector("i.wb-icon"); + if (iconSpan) { + this._createIcon(tree.iconMap, nodeElem, iconSpan, !expanderSpan); + } + } + // Adjust column width + if (opts.resizeCols !== false && !this.isColspan()) { + const colElems = rowDiv.querySelectorAll("span.wb-col"); + let idx = 0; + let ofs = 0; + for (const colDef of this.tree.columns) { + const colElem = colElems[idx]; + colElem.style.left = `${ofs}px`; + colElem.style.width = `${colDef._widthPx}px`; + idx++; + ofs += colDef._widthPx; + } + } + } + /* + * Create or update node's markup. + * + * `options.change` defaults to ChangeType.data, which updates the title, + * icon, and status. It also triggers the `render` event, that lets the user + * create or update the content of embeded cell elements. + * + * If only the status or other class-only modifications have changed, + * `options.change` should be set to ChangeType.status instead for best + * efficiency. + * + * Calling `update()` is almost always a better alternative. + * @see {@link WunderbaumNode.update} + */ + _render(options) { + // this.log("render", options); + const opts = Object.assign({ change: ChangeType.data }, options); + if (!this._rowElem) { + opts.change = ChangeType.row; + } + switch (opts.change) { + case "status": + this._render_status(opts); + break; + case "data": + this._render_data(opts); + break; + case "row": + // _rowElem is not yet created (asserted in _render_markup) + this._render_markup(opts); + break; + default: + error(`Invalid change type '${opts.change}'.`); + } + } + /** + * Remove all children, collapse, and set the lazy-flag, so that the lazyLoad + * event is triggered on next expand. + */ + resetLazy() { + this.removeChildren(); + this.expanded = false; + this.lazy = true; + this.children = null; + this.tree.update(ChangeType.structure); + } + /** Convert node (or whole branch) into a plain object. + * + * The result is compatible with node.addChildren(). + * + * @param include child nodes + * @param callback(dict, node) is called for every node, in order to allow + * modifications. + * Return `false` to ignore this node or `"skip"` to include this node + * without its children. + * @see {@link Wunderbaum.toDictArray}. + */ + toDict(recursive = false, callback) { + const dict = {}; + NODE_DICT_PROPS.forEach((propName) => { + const val = this[propName]; + if (val instanceof Set) { + // Convert Set to string (or skip if set is empty) + val.size + ? (dict[propName] = Array.prototype.join.call(val.keys(), " ")) + : 0; + } + else if (val || val === false || val === 0) { + dict[propName] = val; + } + }); + if (!isEmptyObject(this.data)) { + dict.data = extend({}, this.data); + if (isEmptyObject(dict.data)) { + delete dict.data; + } + } + if (callback) { + const res = callback(dict, this); + if (res === false) { + // Note: a return value of `false` is only used internally + return false; // Don't include this node nor its children + } + if (res === "skip") { + recursive = false; // Include this node, but not the children + } + } + if (recursive) { + if (isArray(this.children)) { + dict.children = []; + for (let i = 0, l = this.children.length; i < l; i++) { + const node = this.children[i]; + if (!node.isStatusNode()) { + // Note: a return value of `false` is only used internally + const res = node.toDict(true, callback); + if (res !== false) { + dict.children.push(res); + } + } + } + } + } + return dict; + } + /** Return an option value that has a default, but may be overridden by a + * callback or a node instance attribute. + * + * Evaluation sequence: + * + * - If `tree.options.` is a callback that returns something, use that. + * - Else if `node.` is defined, use that. + * - Else if `tree.types[]` is a value, use that. + * - Else if `tree.options.` is a value, use that. + * - Else use `defaultValue`. + * + * @param name name of the option property (on node and tree) + * @param defaultValue return this if nothing else matched + * {@link Wunderbaum.getOption|Wunderbaum.getOption()} + */ + getOption(name, defaultValue) { + const tree = this.tree; + let opts = tree.options; + // Lookup `name` in options dict + if (name.indexOf(".") >= 0) { + [opts, name] = name.split("."); + } + const value = opts[name]; // ?? defaultValue; + // A callback resolver always takes precedence + if (typeof value === "function") { + const res = value.call(tree, { + type: "resolve", + tree: tree, + node: this, + // typeInfo: this.type ? tree.types[this.type] : {}, + }); + if (res !== undefined) { + return res; + } + } + // If this node has an explicit local setting, use it: + if (this[name] !== undefined) { + return this[name]; + } + // Use value from type definition if defined + const typeInfo = this.type ? tree.types[this.type] : undefined; + const res = typeInfo ? typeInfo[name] : undefined; + if (res !== undefined) { + return res; + } + // Use value from value options dict, fallback do default + return value !== null && value !== void 0 ? value : defaultValue; + } + /** Make sure that this node is visible in the viewport. + * @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo()} + */ + async scrollIntoView(options) { + const opts = Object.assign({ node: this }, options); + return this.tree.scrollTo(opts); + } + /** + * Activate this node, deactivate previous, send events, activate column and + * scroll into viewport. + */ + async setActive(flag = true, options) { + const tree = this.tree; + const prev = tree.getActiveNode(); + const retrigger = options === null || options === void 0 ? void 0 : options.retrigger; // Default: false + const focusTree = options === null || options === void 0 ? void 0 : options.focusTree; // Default: false + // const focusNode = options?.focusNode !== false; // Default: true + const noEvents = options === null || options === void 0 ? void 0 : options.noEvents; // Default: false + const orgEvent = options === null || options === void 0 ? void 0 : options.event; // Default: null + const colIdx = options === null || options === void 0 ? void 0 : options.colIdx; // Default: null + const edit = options === null || options === void 0 ? void 0 : options.edit; // Default: false + assert(!colIdx || tree.isCellNav(), "colIdx requires cellNav"); + assert(!edit || colIdx != null, "edit requires colIdx"); + if (!noEvents) { + if (flag) { + if (prev !== this || retrigger) { + if ((prev === null || prev === void 0 ? void 0 : prev._callEvent("deactivate", { + nextNode: this, + event: orgEvent, + })) === false || + this._callEvent("beforeActivate", { + prevNode: prev, + event: orgEvent, + }) === false) { + return; + } + tree._setActiveNode(null); + prev === null || prev === void 0 ? void 0 : prev.update(ChangeType.status); + } + } + else if (prev === this || retrigger) { + this._callEvent("deactivate", { nextNode: null, event: orgEvent }); + } + } + if (prev !== this) { + if (flag) { + tree._setActiveNode(this); + } + prev === null || prev === void 0 ? void 0 : prev.update(ChangeType.status); + this.update(ChangeType.status); + } + return this.makeVisible().then(() => { + if (flag) { + if (focusTree || edit) { + tree.setFocus(); + tree._setFocusNode(this); + tree.focusNode.setFocus(); + } + // if (focusNode || edit) { + // tree.focusNode = this; + // tree.focusNode.setFocus(); + // } + if (colIdx != null && tree.isCellNav()) { + tree.setColumn(colIdx, { edit: edit }); + } + if (!noEvents) { + this._callEvent("activate", { prevNode: prev, event: orgEvent }); + } + } + }); + } + /** + * Expand or collapse this node. + */ + async setExpanded(flag = true, options) { + const { force, scrollIntoView, immediate } = options !== null && options !== void 0 ? options : {}; + const sendEvents = !(options === null || options === void 0 ? void 0 : options.noEvents); // Default: send events + if (!flag && + this.isExpanded() && + this.getLevel() <= this.tree.getOption("minExpandLevel") && + !force) { + this.logDebug("Ignored collapse request below minExpandLevel."); + return; + } + if (!flag === !this.expanded) { + return; // Nothing to do + } + if (sendEvents && + this._callEvent("beforeExpand", { flag: flag }) === false) { + return; + } + // this.log("setExpanded()"); + if (flag && this.getOption("autoCollapse")) { + this.collapseSiblings(options); + } + if (flag && this.lazy && this.children == null) { + await this.loadLazy(); + } + this.expanded = flag; + const updateOpts = { immediate: immediate }; + // const updateOpts = { immediate: !!util.getOption(options, "immediate") }; + this.tree.update(ChangeType.structure, updateOpts); + if (flag && scrollIntoView) { + const lastChild = this.getLastChild(); + if (lastChild) { + this.tree.updatePendingModifications(); + lastChild.scrollIntoView({ topNode: this }); + } + } + if (sendEvents) { + this._callEvent("expand", { flag: flag }); + } + } + /** + * Set keyboard focus here. + * @see {@link setActive} + */ + setFocus(flag = true) { + assert(!!flag, "Blur is not yet implemented"); + const prev = this.tree.focusNode; + this.tree._setFocusNode(this); + prev === null || prev === void 0 ? void 0 : prev.update(); + this.update(); + } + /** Set a new icon path or class. */ + setIcon(icon) { + this.icon = icon; + this.update(); + } + /** Change node's {@link key} and/or {@link refKey}. */ + setKey(key, refKey) { + throw new Error("Not yet implemented"); + } + /** + * Trigger a repaint, typically after a status or data change. + * + * `change` defaults to 'data', which handles modifcations of title, icon, + * and column content. It can be reduced to 'ChangeType.status' if only + * active/focus/selected state has changed. + * + * This method will eventually call {@link WunderbaumNode._render()} with + * default options, but may be more consistent with the tree's + * {@link Wunderbaum.update()} API. + */ + update(change = ChangeType.data) { + assert(change === ChangeType.status || change === ChangeType.data, `Invalid change type ${change}`); + this.tree.update(change, this); + } + /** + * Return an array of selected nodes. + * @param stopOnParents only return the topmost selected node (useful with selectMode 'hier') + */ + getSelectedNodes(stopOnParents = false) { + const nodeList = []; + this.visit((node) => { + if (node.selected) { + nodeList.push(node); + if (stopOnParents === true) { + return "skip"; // stop processing this branch + } + } + }); + return nodeList; + } + /** Toggle the check/uncheck state. */ + toggleSelected(options) { + let flag = this.isSelected(); + if (flag === undefined && !this.isRadio()) { + flag = this._anySelectable(); + } + else { + flag = !flag; + } + return this.setSelected(flag, options); + } + /** Return true if at least on selectable descendant end-node is unselected. @internal */ + _anySelectable() { + let found = false; + this.visit((node) => { + if (node.selected === false && + !node.unselectable && + !node.hasChildren() && + !node.parent.radiogroup) { + found = true; + return false; // Stop iteration + } + }); + return found; + } + /* Apply selection state to a single node. */ + _changeSelectStatusProps(state) { + let changed = false; + switch (state) { + case false: + changed = this.selected || this._partsel; + this.selected = false; + this._partsel = false; + break; + case true: + changed = !this.selected || !this._partsel; + this.selected = true; + this._partsel = true; + break; + case undefined: + changed = this.selected || !this._partsel; + this.selected = false; + this._partsel = true; + break; + default: + error(`Invalid state: ${state}`); + } + if (changed) { + this.update(); + } + return changed; + } + /** + * Fix selection status, after this node was (de)selected in `selectMode: 'hier'`. + * This includes (de)selecting all descendants. + */ + fixSelection3AfterClick(opts) { + const force = !!(opts === null || opts === void 0 ? void 0 : opts.force); + const flag = this.isSelected(); + this.visit((node) => { + if (node.radiogroup) { + return "skip"; // Don't (de)select this branch + } + if (force || !node.getOption("unselectable")) { + node._changeSelectStatusProps(flag); + } + }); + this.fixSelection3FromEndNodes(); + } + /** + * Fix selection status for multi-hier mode. + * Only end-nodes are considered to update the descendants branch and parents. + * Should be called after this node has loaded new children or after + * children have been modified using the API. + */ + fixSelection3FromEndNodes(opts) { + const force = !!(opts === null || opts === void 0 ? void 0 : opts.force); + assert(this.tree.options.selectMode === "hier", "expected selectMode 'hier'"); + // Visit all end nodes and adjust their parent's `selected` and `_partsel` + // attributes. Return selection state true, false, or undefined. + const _walk = (node) => { + let state; + const children = node.children; + if (children && children.length) { + // check all children recursively + let allSelected = true; + let someSelected = false; + for (let i = 0, l = children.length; i < l; i++) { + const child = children[i]; + // the selection state of a node is not relevant; we need the end-nodes + const s = _walk(child); + if (s !== false) { + someSelected = true; + } + if (s !== true) { + allSelected = false; + } + } + state = allSelected ? true : someSelected ? undefined : false; + } + else { + // This is an end-node: simply report the status + state = !!node.selected; + } + // #939: Keep a `_partsel` flag that was explicitly set on a lazy node + if (node._partsel && + !node.selected && + node.lazy && + node.children == null) { + state = undefined; + } + if (force || !node.getOption("unselectable")) { + node._changeSelectStatusProps(state); + } + return state; + }; + _walk(this); + // Update parent's state + this.visitParents((node) => { + let state; + const children = node.children; + let allSelected = true; + let someSelected = false; + for (let i = 0, l = children.length; i < l; i++) { + const child = children[i]; + state = !!child.selected; + // When fixing the parents, we trust the sibling status (i.e. we don't recurse) + if (state || child._partsel) { + someSelected = true; + } + if (!state) { + allSelected = false; + } + } + state = allSelected ? true : someSelected ? undefined : false; + node._changeSelectStatusProps(state); + }); + } + /** Modify the check/uncheck state. */ + setSelected(flag = true, options) { + const tree = this.tree; + const sendEvents = !(options === null || options === void 0 ? void 0 : options.noEvents); // Default: send events + const prev = this.isSelected(); + const isRadio = this.parent && this.parent.radiogroup; + const selectMode = tree.options.selectMode; + const canSelect = (options === null || options === void 0 ? void 0 : options.force) || !this.getOption("unselectable"); + flag = !!flag; + // this.logDebug(`setSelected(${flag})`, this); + if (!canSelect) { + return prev; + } + if ((options === null || options === void 0 ? void 0 : options.propagateDown) && selectMode === "multi") { + tree.runWithDeferredUpdate(() => { + this.visit((node) => { + node.setSelected(flag); + }); + }); + return prev; + } + if (flag === prev || + (sendEvents && this._callEvent("beforeSelect", { flag: flag }) === false)) { + return prev; + } + tree.runWithDeferredUpdate(() => { + if (isRadio) { + // Radiobutton Group + if (!flag && !(options === null || options === void 0 ? void 0 : options.force)) { + return prev; // don't uncheck radio buttons + } + for (const sibling of this.parent.children) { + sibling.selected = sibling === this; + } + } + else { + this.selected = flag; + if (selectMode === "hier") { + this.fixSelection3AfterClick(); + } + else if (selectMode === "single") { + tree.visit((n) => { + n.selected = false; + }); + } + } + }); + if (sendEvents) { + this._callEvent("select", { flag: flag }); + } + return prev; + } + /** Display node status (ok, loading, error, noData) using styles and a dummy child node. */ + setStatus(status, options) { + const tree = this.tree; + const message = options === null || options === void 0 ? void 0 : options.message; + const details = options === null || options === void 0 ? void 0 : options.details; + let statusNode = null; + const _clearStatusNode = () => { + // Remove dedicated dummy node, if any + const children = this.children; + if (children && children.length && children[0].isStatusNode()) { + children[0].remove(); + } + }; + const _setStatusNode = (data) => { + // Create/modify the dedicated dummy node for 'loading...' or + // 'error!' status. (only called for direct child of the invisible + // system root) + const children = this.children; + const firstChild = children ? children[0] : null; + assert(data.statusNodeType, "Not a status node"); + assert(!firstChild || !firstChild.isStatusNode(), "Child must not be a status node"); + statusNode = this.addNode(data, "prependChild"); + statusNode.match = true; + tree.update(ChangeType.structure); + return statusNode; + }; + _clearStatusNode(); + switch (status) { + case "ok": + this._isLoading = false; + this._errorInfo = null; + break; + case "loading": + this._isLoading = true; + this._errorInfo = null; + if (this.parent) { + this.update(ChangeType.status); + } + else { + // If this is the invisible root, add a visible top-level node + _setStatusNode({ + statusNodeType: status, + title: tree.options.strings.loading + + (message ? " (" + message + ")" : ""), + checkbox: false, + colspan: true, + tooltip: details, + }); + } + // this.update(); + break; + case "error": + _setStatusNode({ + statusNodeType: status, + title: tree.options.strings.loadError + + (message ? " (" + message + ")" : ""), + checkbox: false, + colspan: true, + // classes: "wb-center", + tooltip: details, + }); + this._isLoading = false; + this._errorInfo = { message: message, details: details }; + break; + case "noData": + _setStatusNode({ + statusNodeType: status, + title: message || tree.options.strings.noData, + checkbox: false, + colspan: true, + tooltip: details, + }); + this._isLoading = false; + this._errorInfo = null; + break; + default: + error("invalid node status " + status); + } + tree.update(ChangeType.structure); + return statusNode; + } + /** Rename this node. */ + setTitle(title) { + this.title = title; + this.update(); + // this.triggerModify("rename"); // TODO + } + _sortChildren(cmp, deep) { + const cl = this.children; + if (!cl) { + return; + } + cl.sort(cmp); + if (deep) { + for (let i = 0, l = cl.length; i < l; i++) { + if (cl[i].children) { + cl[i]._sortChildren(cmp, deep); + } + } + } + } + /** + * Sort child list by title or custom criteria. + * @param {function} cmp custom compare function(a, b) that returns -1, 0, or 1 + * (defaults to sorting by title). + * @param {boolean} deep pass true to sort all descendant nodes recursively + */ + sortChildren(cmp = nodeTitleSorter, deep = false) { + this._sortChildren(cmp || nodeTitleSorter, deep); + this.tree.update(ChangeType.structure); + // this.triggerModify("sort"); // TODO + } + /** + * Trigger `modifyChild` event on a parent to signal that a child was modified. + * @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ... + */ + triggerModifyChild(operation, child, extra) { + this.logDebug(`modifyChild(${operation})`, extra, child); + if (!this.tree.options.modifyChild) { + return; + } + if (child && child.parent !== this) { + error("child " + child + " is not a child of " + this); + } + this._callEvent("modifyChild", extend({ operation: operation, child: child }, extra)); + } + /** + * Trigger `modifyChild` event on node.parent(!). + * @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ... + * @param {object} [extra] + */ + triggerModify(operation, extra) { + // if (!this.parent) { + // return; + // } + this.parent.triggerModifyChild(operation, this, extra); + } + /** + * Call `callback(node)` for all descendant nodes in hierarchical order (depth-first, pre-order). + * + * Stop iteration, if fn() returns false. Skip current branch, if fn() + * returns "skip".
    + * Return false if iteration was stopped. + * + * @param {function} callback the callback function. + * Return false to stop iteration, return "skip" to skip this node and + * its children only. + * @see {@link IterableIterator}, {@link Wunderbaum.visit}. + */ + visit(callback, includeSelf = false) { + let res = true; + const children = this.children; + if (includeSelf === true) { + res = callback(this); + if (res === false || res === "skip") { + return res; + } + } + if (children) { + for (let i = 0, l = children.length; i < l; i++) { + res = children[i].visit(callback, true); + if (res === false) { + break; + } + } + } + return res; + } + /** Call fn(node) for all parent nodes, bottom-up, including invisible system root.
    + * Stop iteration, if callback() returns false.
    + * Return false if iteration was stopped. + * + * @param callback the callback function. Return false to stop iteration + */ + visitParents(callback, includeSelf = false) { + if (includeSelf && callback(this) === false) { + return false; + } + let p = this.parent; + while (p) { + if (callback(p) === false) { + return false; + } + p = p.parent; + } + return true; + } + /** + * Call fn(node) for all sibling nodes.
    + * Stop iteration, if fn() returns false.
    + * Return false if iteration was stopped. + * + * @param {function} fn the callback function. + * Return false to stop iteration. + */ + visitSiblings(callback, includeSelf = false) { + const ac = this.parent.children; + for (let i = 0, l = ac.length; i < l; i++) { + const n = ac[i]; + if (includeSelf || n !== this) { + if (callback(n) === false) { + return false; + } + } + } + return true; + } + /** + * [ext-filter] Return true if this node is matched by current filter (or no filter is active). + */ + isMatched() { + return !(this.tree.filterMode && !this.match); + } + } + WunderbaumNode.sequence = 0; + + /*! + * Wunderbaum - ext-edit + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ + // const START_MARKER = "\uFFF7"; + class EditExtension extends WunderbaumExtension { + constructor(tree) { + super(tree, "edit", { + debounce: 100, + minlength: 1, + maxlength: null, + trigger: [], + trim: true, + select: true, + slowClickDelay: 1000, + validity: true, + // --- Events --- + // (note: there is also the `tree.change` event.) + beforeEdit: null, + edit: null, + apply: null, + }); + this.curEditNode = null; + this.relatedNode = null; + this.debouncedOnChange = debounce(this._onChange.bind(this), this.getPluginOption("debounce")); + } + /* + * Call an event handler, while marking the current node cell 'busy'. + * Deal with returned promises and ValidationError. + * Convert a ValidationError into a input.setCustomValidity() call and vice versa. + */ + async _applyChange(eventName, node, colElem, inputElem, extra) { + node.log(`_applyChange(${eventName})`, extra); + colElem.classList.add("wb-busy"); + colElem.classList.remove("wb-error", "wb-invalid"); + inputElem.setCustomValidity(""); + // Call event handler either ('change' or 'edit.appy'), which may return a + // promise or a scalar value or throw a ValidationError. + return new Promise((resolve, reject) => { + const res = node._callEvent(eventName, extra); + // normalize to promise, even if a scalar value was returned and await it + Promise.resolve(res) + .then((res) => { + resolve(res); + }) + .catch((err) => { + reject(err); + }); + }) + .then((res) => { + if (!inputElem.checkValidity()) { + // Native validation failed or handler called 'inputElem.setCustomValidity()' + node.logWarn("inputElem.checkValidity() failed: throwing...."); + throw new ValidationError(inputElem.validationMessage); + } + return res; + }) + .catch((err) => { + if (err instanceof ValidationError) { + node.logWarn("catched ", err); + colElem.classList.add("wb-invalid"); + if (inputElem.setCustomValidity && !inputElem.validationMessage) { + inputElem.setCustomValidity(err.message); + } + if (inputElem.validationMessage) { + inputElem.reportValidity(); + } + // throw err; + } + else { + node.logError(`Error in ${eventName} event handler (throw e.util.ValidationError instead if this was intended)`, err); + colElem.classList.add("wb-error"); + throw err; + } + }) + .finally(() => { + colElem.classList.remove("wb-busy"); + }); + } + /* + * Called for when a control that is embedded in a cell fires a `change` event. + */ + _onChange(e) { + const info = Wunderbaum.getEventInfo(e); + const node = info.node; + const colElem = info.colElem; + if (!node || info.colIdx === 0) { + this.tree.log("Ignored change event for removed element or node title"); + return; + } + // See also WbChangeEventType + this._applyChange("change", node, colElem, e.target, { + info: info, + event: e, + inputElem: e.target, + inputValue: Wunderbaum.util.getValueFromElem(e.target), + inputValid: e.target.checkValidity(), + }); + } + init() { + super.init(); + onEvent(this.tree.element, "change", //"change input", + ".contenteditable,input,textarea,select", + // #61: we must not debounce the `change`, event.target may be reset to null + // when the debounced handler is called. + // (e) => { + // this.debouncedOnChange(e); + // } + (e) => this._onChange(e)); + } + /* Called by ext_keynav to pre-process input. */ + _preprocessKeyEvent(data) { + const event = data.event; + const eventName = eventToString(event); + const tree = this.tree; + const trigger = this.getPluginOption("trigger"); + // const inputElem = + // event.target && event.target.closest("input,[contenteditable]"); + // tree.logDebug(`_preprocessKeyEvent: ${eventName}, editing:${this.isEditingTitle()}`); + // --- Title editing: apply/discard --- + // if (inputElem) { + if (this.isEditingTitle()) { + switch (eventName) { + case "Enter": + this._stopEditTitle(true, { event: event }); + return false; + case "Escape": + this._stopEditTitle(false, { event: event }); + return false; + } + // If the event target is an input element or `contenteditable="true"`, + // we ignore it as navigation command + return false; + } + // --- Trigger title editing + if (tree.isRowNav() || tree.activeColIdx === 0) { + switch (eventName) { + case "Enter": + if (trigger.indexOf("macEnter") >= 0 && isMac) { + this.startEditTitle(); + return false; + } + break; + case "F2": + if (trigger.indexOf("F2") >= 0) { + this.startEditTitle(); + return false; + } + break; + } + return true; + } + return true; + } + /** Return true if a title is currently being edited. */ + isEditingTitle(node) { + return node ? this.curEditNode === node : !!this.curEditNode; + } + /** Start renaming, i.e. replace the title with an embedded ``. */ + startEditTitle(node) { + node = node !== null && node !== void 0 ? node : this.tree.getActiveNode(); + const validity = this.getPluginOption("validity"); + const select = this.getPluginOption("select"); + if (!node) { + return; + } + this.tree.logDebug(`startEditTitle(node=${node})`); + let inputHtml = node._callEvent("edit.beforeEdit"); + if (inputHtml === false) { + node.logDebug("beforeEdit canceled operation."); + return; + } + // `beforeEdit(e)` may return an input HTML string. Otherwise use a default + // (we also treat a `true` return value as 'use default'): + if (inputHtml === true || !inputHtml) { + const title = escapeHtml(node.title); + let opt = this.getPluginOption("maxlength"); + const maxlength = opt ? ` maxlength="${opt}"` : ""; + opt = this.getPluginOption("minlength"); + const minlength = opt ? ` minlength="${opt}"` : ""; + const required = opt > 0 ? " required" : ""; + inputHtml = + ``; + } + const titleSpan = node + .getColElem(0) + .querySelector(".wb-title"); + titleSpan.innerHTML = inputHtml; + const inputElem = titleSpan.firstElementChild; + if (validity) { + // Permanently apply input validations (CSS and tooltip) + inputElem.addEventListener("keydown", (e) => { + inputElem.setCustomValidity(""); + if (!inputElem.reportValidity()) { + node.logWarn(`Invalid input: '${inputElem.value}'`); + } + }); + } + inputElem.focus(); + if (select) { + inputElem.select(); + } + this.curEditNode = node; + node._callEvent("edit.edit", { + inputElem: inputElem, + }); + } + /** + * + * @param apply + * @returns + */ + stopEditTitle(apply) { + return this._stopEditTitle(apply, {}); + } + /* + * + * @param apply + * @param opts.canKeepOpen + */ + _stopEditTitle(apply, options) { + options !== null && options !== void 0 ? options : (options = {}); + const focusElem = document.activeElement; + let newValue = focusElem ? getValueFromElem(focusElem) : null; + const node = this.curEditNode; + const forceClose = !!options.forceClose; + const validity = this.getPluginOption("validity"); + if (newValue && this.getPluginOption("trim")) { + newValue = newValue.trim(); + } + if (!node) { + this.tree.logDebug("stopEditTitle: not in edit mode."); + return; + } + node.logDebug(`stopEditTitle(${apply})`, options, focusElem, newValue); + if (apply && newValue !== null && newValue !== node.title) { + const errMsg = focusElem.validationMessage; + if (errMsg) { + // input element's native validation failed + throw new Error(`Input validation failed for "${newValue}": ${errMsg}.`); + } + const colElem = node.getColElem(0); + this._applyChange("edit.apply", node, colElem, focusElem, { + oldValue: node.title, + newValue: newValue, + inputElem: focusElem, + inputValid: focusElem.checkValidity(), + }).then((value) => { + const errMsg = focusElem.validationMessage; + if (validity && errMsg && value !== false) { + // Handler called 'inputElem.setCustomValidity()' to signal error + throw new Error(`Edit apply validation failed for "${newValue}": ${errMsg}.`); + } + // Discard the embedded `` + // node.logDebug("applyChange:", value, forceClose) + if (!forceClose && value === false) { + // Keep open + return; + } + node === null || node === void 0 ? void 0 : node.setTitle(newValue); + // NOTE: At least on Safari, this render call triggers a scroll event + // probably because the focused input is replaced. + this.curEditNode._render({ preventScroll: true }); + this.curEditNode = null; + this.relatedNode = null; + this.tree.setFocus(); // restore focus that was in the input element + }); + // .catch((err) => { + // node.logError(err); + // }); + // Trigger 'change' event for embedded `` + // focusElem.blur(); + } + else { + // Discard the embedded `` + // NOTE: At least on Safari, this render call triggers a scroll event + // probably because the focused input is replaced. + this.curEditNode._render({ preventScroll: true }); + this.curEditNode = null; + this.relatedNode = null; + // We discarded the , so we have to acquire keyboard focus again + this.tree.setFocus(); + } + } + /** + * Create a new child or sibling node and start edit mode. + */ + createNode(mode = "after", node, init) { + const tree = this.tree; + node = node !== null && node !== void 0 ? node : tree.getActiveNode(); + assert(node, "No node was passed, or no node is currently active."); + // const validity = this.getPluginOption("validity"); + mode = mode || "prependChild"; + if (init == null) { + init = { title: "" }; + } + else if (typeof init === "string") { + init = { title: init }; + } + else { + assert(isPlainObject(init), `Expected a plain object: ${init}`); + } + // Make sure node is expanded (and loaded) in 'child' mode + if ((mode === "prependChild" || mode === "appendChild") && + (node === null || node === void 0 ? void 0 : node.isExpandable(true))) { + node.setExpanded().then(() => { + this.createNode(mode, node, init); + }); + return; + } + const newNode = node.addNode(init, mode); + newNode.setClass("wb-edit-new"); + this.relatedNode = node; + // Don't filter new nodes: + newNode.match = true; + newNode.makeVisible({ noAnimation: true }).then(() => { + this.startEditTitle(newNode); + }); + } + } + + /*! + * wunderbaum.ts + * + * A treegrid control. + * + * Copyright (c) 2021-2023, Martin Wendt (https://wwWendt.de). + * https://github.com/mar10/wunderbaum + * + * Released under the MIT license. + * @version v0.8.2 + * @date Sat, 17 Feb 2024 07:32:06 GMT + */ + // import "./wunderbaum.scss"; + class WbSystemRoot extends WunderbaumNode { + constructor(tree) { + super(tree, null, { + key: "__root__", + title: tree.id, + }); + } + toString() { + return `WbSystemRoot@${this.key}<'${this.tree.id}'>`; + } + } + /** + * A persistent plain object or array. + * + * See also {@link WunderbaumOptions}. + */ + class Wunderbaum { + /** Currently active node if any. + * Use @link {WunderbaumNode.setActive|setActive} to modify. + */ + get activeNode() { + var _a; + // Check for deleted node, i.e. node.tree === null + return ((_a = this._activeNode) === null || _a === void 0 ? void 0 : _a.tree) ? this._activeNode : null; + } + /** Current node hat has keyboard focus if any. + * Use @link {WunderbaumNode.setFocus|setFocus()} to modify. + */ + get focusNode() { + var _a; + // Check for deleted node, i.e. node.tree === null + return ((_a = this._focusNode) === null || _a === void 0 ? void 0 : _a.tree) ? this._focusNode : null; + } + constructor(options) { + this.enabled = true; + /** Contains additional data that was sent as response to an Ajax source load request. */ + this.data = {}; + this.extensionList = []; + this.extensions = {}; + this.keyMap = new Map(); + this.refKeyMap = new Map(); + this.treeRowCount = 0; + this._disableUpdateCount = 0; + this._disableUpdateIgnoreCount = 0; + this._activeNode = null; + this._focusNode = null; + /** Shared properties, referenced by `node.type`. */ + this.types = {}; + /** List of column definitions. */ + this.columns = []; // any[] = []; + this._columnsById = {}; + // Modification Status + this.pendingChangeTypes = new Set(); + /** Expose some useful methods of the util.ts module as `tree._util`. */ + this._util = util; + // --- SELECT --- + // /** @internal */ + // public selectRangeAnchor: WunderbaumNode | null = null; + // --- FILTER --- + this.filterMode = null; + // --- KEYNAV --- + /** @internal Use `setColumn()`/`getActiveColElem()` to access. */ + this.activeColIdx = 0; + /** @internal */ + this._cellNavMode = false; + /** @internal */ + this.lastQuicksearchTime = 0; + /** @internal */ + this.lastQuicksearchTerm = ""; + // --- EDIT --- + this.lastClickTime = 0; + const opts = (this.options = extend({ + id: null, + source: null, + element: null, + debugLevel: DEFAULT_DEBUGLEVEL, + header: null, + // headerHeightPx: ROW_HEIGHT, + rowHeightPx: ROW_HEIGHT, + iconMap: "bootstrap", + columns: null, + types: null, + // escapeTitles: true, + enabled: true, + fixedCol: false, + showSpinner: false, + checkbox: false, + minExpandLevel: 0, + emptyChildListExpandable: false, + // updateThrottleWait: 200, + skeleton: false, + connectTopBreadcrumb: null, + selectMode: "multi", + // --- KeyNav --- + navigationModeOption: null, + quicksearch: true, + // --- Events --- + iconBadge: null, + change: null, + // enhanceTitle: null, + error: null, + receive: null, + // --- Strings --- + strings: { + loadError: "Error", + loading: "Loading...", + // loading: "Loading…", + noData: "No data", + }, + }, options)); + const readyDeferred = new Deferred(); + this.ready = readyDeferred.promise(); + let readyOk = false; + this.ready + .then(() => { + readyOk = true; + try { + this._callEvent("init"); + } + catch (error) { + // We re-raise in the reject handler, but Chrome resets the stack + // frame then, so we log it here: + this.logError("Exception inside `init(e)` event:", error); + } + }) + .catch((err) => { + if (readyOk) { + // Error occurred in `init` handler. We can re-raise, but Chrome + // resets the stack frame. + throw err; + } + else { + // Error in load process + this._callEvent("init", { error: err }); + } + }); + this.id = opts.id || "wb_" + ++Wunderbaum.sequence; + this.root = new WbSystemRoot(this); + this._registerExtension(new KeynavExtension(this)); + this._registerExtension(new EditExtension(this)); + this._registerExtension(new FilterExtension(this)); + this._registerExtension(new DndExtension(this)); + this._registerExtension(new GridExtension(this)); + this._registerExtension(new LoggerExtension(this)); + this._updateViewportThrottled = adaptiveThrottle(this._updateViewportImmediately.bind(this), {}); + // --- Evaluate options + this.columns = opts.columns; + delete opts.columns; + if (!this.columns || !this.columns.length) { + const title = typeof opts.header === "string" ? opts.header : this.id; + this.columns = [{ id: "*", title: title, width: "*" }]; + } + if (opts.types) { + this.setTypes(opts.types, true); + } + delete opts.types; + // --- Create Markup + this.element = elemFromSelector(opts.element); + assert(!!this.element, `Invalid 'element' option: ${opts.element}`); + this.element.classList.add("wunderbaum"); + if (!this.element.getAttribute("tabindex")) { + this.element.tabIndex = 0; + } + // Attach tree instance to
    + this.element._wb_tree = this; + // Create header markup, or take it from the existing html + this.headerElement = this.element.querySelector("div.wb-header"); + const wantHeader = opts.header == null ? this.columns.length > 1 : !!opts.header; + if (this.headerElement) { + // User existing header markup to define `this.columns` + assert(!this.columns, "`opts.columns` must not be set if markup already contains a header"); + this.columns = []; + const rowElement = this.headerElement.querySelector("div.wb-row"); + for (const colDiv of rowElement.querySelectorAll("div")) { + this.columns.push({ + id: colDiv.dataset.id || `col_${this.columns.length}`, + // id: colDiv.dataset.id || null, + title: "" + colDiv.textContent, + // text: "" + colDiv.textContent, + width: "*", // TODO: read from header span + }); + } + } + else { + // We need a row div, the rest will be computed from `this.columns` + const coldivs = "".repeat(this.columns.length); + this.element.innerHTML = ` +
    +
    + ${coldivs} +
    +
    `; + if (!wantHeader) { + const he = this.element.querySelector("div.wb-header"); + he.style.display = "none"; + } + } + // + this.element.innerHTML += ` +
    +
    +
    `; + this.listContainerElement = this.element.querySelector("div.wb-list-container"); + this.nodeListElement = this.listContainerElement.querySelector("div.wb-node-list"); + this.headerElement = this.element.querySelector("div.wb-header"); + this.element.classList.toggle("wb-grid", this.columns.length > 1); + this._initExtensions(); + // --- apply initial options + ["enabled", "fixedCol"].forEach((optName) => { + if (opts[optName] != null) { + this.setOption(optName, opts[optName]); + } + }); + // --- Load initial data + if (opts.source) { + if (opts.showSpinner) { + this.nodeListElement.innerHTML = + "loading..."; + } + this.load(opts.source) + .then(() => { + // The source may have defined columns, so we may adjust the nav mode + if (opts.navigationModeOption == null) { + if (this.isGrid()) { + this.setNavigationOption(NavModeEnum.cell); + } + else { + this.setNavigationOption(NavModeEnum.row); + } + } + else { + this.setNavigationOption(opts.navigationModeOption); + } + this.update(ChangeType.structure, { immediate: true }); + readyDeferred.resolve(); + }) + .catch((error) => { + readyDeferred.reject(error); + }) + .finally(() => { + var _a; + (_a = this.element.querySelector("progress.spinner")) === null || _a === void 0 ? void 0 : _a.remove(); + this.element.classList.remove("wb-initializing"); + }); + } + else { + readyDeferred.resolve(); + } + // Async mode is sometimes required, because this.element.clientWidth + // has a wrong value at start??? + this.update(ChangeType.any); + // --- Bind listeners + this.element.addEventListener("scroll", (e) => { + // this.log(`scroll, scrollTop:${e.target.scrollTop}`, e); + this.update(ChangeType.scroll); + }); + this.resizeObserver = new ResizeObserver((entries) => { + // this.log("ResizeObserver: Size changed", entries); + this.update(ChangeType.resize); + }); + this.resizeObserver.observe(this.element); + onEvent(this.nodeListElement, "click", "div.wb-row", (e) => { + const info = Wunderbaum.getEventInfo(e); + const node = info.node; + const mouseEvent = e; + // this.log("click", info); + // if (this._selectRange(info) === false) { + // return; + // } + if (this._callEvent("click", { event: e, node: node, info: info }) === false) { + this.lastClickTime = Date.now(); + return false; + } + if (node) { + if (mouseEvent.ctrlKey) { + node.toggleSelected(); + return; + } + // Edit title if 'clickActive' is triggered: + const trigger = this.getOption("edit.trigger"); + const slowClickDelay = this.getOption("edit.slowClickDelay"); + if (trigger.indexOf("clickActive") >= 0 && + info.region === "title" && + node.isActive() && + (!slowClickDelay || Date.now() - this.lastClickTime < slowClickDelay)) { + node.startEditTitle(); + } + if (info.colIdx >= 0) { + node.setActive(true, { colIdx: info.colIdx, event: e }); + } + else { + node.setActive(true, { event: e }); + } + if (info.region === NodeRegion.expander) { + node.setExpanded(!node.isExpanded(), { + scrollIntoView: options.scrollIntoViewOnExpandClick !== false, + }); + } + else if (info.region === NodeRegion.checkbox) { + node.toggleSelected(); + } + } + this.lastClickTime = Date.now(); + }); + onEvent(this.nodeListElement, "dblclick", "div.wb-row", (e) => { + const info = Wunderbaum.getEventInfo(e); + const node = info.node; + // this.log("dblclick", info, e); + if (this._callEvent("dblclick", { event: e, node: node, info: info }) === + false) { + return false; + } + if (node && info.colIdx === 0 && node.isExpandable()) { + this._callMethod("edit._stopEditTitle"); + node.setExpanded(!node.isExpanded()); + } + }); + onEvent(this.element, "keydown", (e) => { + const info = Wunderbaum.getEventInfo(e); + const eventName = eventToString(e); + const node = info.node || this.getFocusNode(); + this._callHook("onKeyEvent", { + event: e, + node: node, + info: info, + eventName: eventName, + }); + }); + onEvent(this.element, "focusin focusout", (e) => { + const flag = e.type === "focusin"; + const targetNode = Wunderbaum.getNode(e); + this._callEvent("focus", { flag: flag, event: e }); + if (flag && this.isRowNav() && !this.isEditingTitle()) { + if (opts.navigationModeOption === NavModeEnum.row) { + targetNode === null || targetNode === void 0 ? void 0 : targetNode.setActive(); + } + else { + this.setCellNav(); + } + } + if (!flag) { + this._callMethod("edit._stopEditTitle", true, { + event: e, + forceClose: true, + }); + } + }); + } + /** + * Return a Wunderbaum instance, from element, id, index, or event. + * + * ```js + * getTree(); // Get first Wunderbaum instance on page + * getTree(1); // Get second Wunderbaum instance on page + * getTree(event); // Get tree for this mouse- or keyboard event + * getTree("foo"); // Get tree for this `tree.options.id` + * getTree("#tree"); // Get tree for first matching element selector + * ``` + */ + static getTree(el) { + if (el instanceof Wunderbaum) { + return el; + } + else if (el instanceof WunderbaumNode) { + return el.tree; + } + if (el === undefined) { + el = 0; // get first tree + } + if (typeof el === "number") { + el = document.querySelectorAll(".wunderbaum")[el]; // el was an integer: return nth element + } + else if (typeof el === "string") { + // Search all trees for matching ID + for (const treeElem of document.querySelectorAll(".wunderbaum")) { + const tree = treeElem._wb_tree; + if (tree && tree.id === el) { + return tree; + } + } + // Search by selector + el = document.querySelector(el); + if (!el) { + return null; + } + } + else if (el.target) { + el = el.target; + } + assert(el instanceof Element, `Invalid el type: ${el}`); + if (!el.matches(".wunderbaum")) { + el = el.closest(".wunderbaum"); + } + if (el && el._wb_tree) { + return el._wb_tree; + } + return null; + } + /** + * Return the icon-function -> icon-definition mapping. + */ + get iconMap() { + const map = this.options.iconMap; + if (typeof map === "string") { + return iconMaps[map]; + } + return map; + } + /** + * Return a WunderbaumNode instance from element or event. + */ + static getNode(el) { + if (!el) { + return null; + } + else if (el instanceof WunderbaumNode) { + return el; + } + else if (el.target !== undefined) { + el = el.target; // el was an Event + } + // `el` is a DOM element + // let nodeElem = obj.closest("div.wb-row"); + while (el) { + if (el._wb_node) { + return el._wb_node; + } + el = el.parentElement; //.parentNode; + } + return null; + } + /** + * Iterate all descendant nodes depth-first, pre-order using `for ... of ...` syntax. + * More concise, but slightly slower than {@link Wunderbaum.visit}. + * + * Example: + * ```js + * for(const node of tree) { + * ... + * } + * ``` + */ + *[Symbol.iterator]() { + yield* this.root; + } + /** @internal */ + _registerExtension(extension) { + this.extensionList.push(extension); + this.extensions[extension.id] = extension; + // this.extensionMap.set(extension.id, extension); + } + /** Called on tree (re)init after markup is created, before loading. */ + _initExtensions() { + for (const ext of this.extensionList) { + ext.init(); + } + } + /** Add node to tree's bookkeeping data structures. */ + _registerNode(node) { + const key = node.key; + assert(key != null, `Missing key: '${node}'.`); + assert(!this.keyMap.has(key), `Duplicate key: '${key}': ${node}.`); + this.keyMap.set(key, node); + const rk = node.refKey; + if (rk != null) { + const rks = this.refKeyMap.get(rk); // Set of nodes with this refKey + if (rks) { + rks.add(node); + } + else { + this.refKeyMap.set(rk, new Set([node])); + } + } + } + /** Remove node from tree's bookkeeping data structures. */ + _unregisterNode(node) { + // Remove refKey reference from map (if any) + const rk = node.refKey; + if (rk != null) { + const rks = this.refKeyMap.get(rk); + if (rks && rks.delete(node) && !rks.size) { + // We just removed the last element + this.refKeyMap.delete(rk); + } + } + // Remove key reference from map + this.keyMap.delete(node.key); + // Mark as disposed + node.tree = null; + node.parent = null; + // Remove HTML markup + node.removeMarkup(); + } + /** Call all hook methods of all registered extensions.*/ + _callHook(hook, data = {}) { + let res; + const d = extend({}, { tree: this, options: this.options, result: undefined }, data); + for (const ext of this.extensionList) { + res = ext[hook].call(ext, d); + if (res === false) { + break; + } + if (d.result !== undefined) { + res = d.result; + } + } + return res; + } + /** + * Call tree method or extension method if defined. + * + * Example: + * ```js + * tree._callMethod("edit.startEdit", "arg1", "arg2") + * ``` + */ + _callMethod(name, ...args) { + const [p, n] = name.split("."); + const obj = n ? this.extensions[p] : this; + const func = obj[n]; + if (func) { + return func.apply(obj, args); + } + else { + this.logError(`Calling undefined method '${name}()'.`); + } + } + /** + * Call event handler if defined in tree or tree.EXTENSION options. + * + * Example: + * ```js + * tree._callEvent("edit.beforeEdit", {foo: 42}) + * ``` + */ + _callEvent(type, extra) { + const [p, n] = type.split("."); + const opts = this.options; + const func = n ? opts[p][n] : opts[p]; + if (func) { + return func.call(this, extend({ type: type, tree: this, util: this._util }, extra)); + // } else { + // this.logError(`Triggering undefined event '${type}'.`) + } + } + /** Return the node for given row index. */ + _getNodeByRowIdx(idx) { + // TODO: start searching from active node (reverse) + let node = null; + this.visitRows((n) => { + if (n._rowIdx === idx) { + node = n; + return false; + } + }); + return node; + } + /** Return the topmost visible node in the viewport. */ + getTopmostVpNode(complete = true) { + const gracePx = 1; // ignore subpixel scrolling + const scrollParent = this.element; + // const headerHeight = this.headerElement.clientHeight; // May be 0 + const scrollTop = scrollParent.scrollTop; // + headerHeight; + let topIdx; + if (complete) { + topIdx = Math.ceil((scrollTop - gracePx) / ROW_HEIGHT); + } + else { + topIdx = Math.floor(scrollTop / ROW_HEIGHT); + } + return this._getNodeByRowIdx(topIdx); + } + /** Return the lowest visible node in the viewport. */ + getLowestVpNode(complete = true) { + const scrollParent = this.element; + const headerHeight = this.headerElement.clientHeight; // May be 0 + const scrollTop = scrollParent.scrollTop; + const clientHeight = scrollParent.clientHeight - headerHeight; + let bottomIdx; + if (complete) { + bottomIdx = Math.floor((scrollTop + clientHeight) / ROW_HEIGHT) - 1; + } + else { + bottomIdx = Math.ceil((scrollTop + clientHeight) / ROW_HEIGHT) - 1; + } + bottomIdx = Math.min(bottomIdx, this.count(true) - 1); + return this._getNodeByRowIdx(bottomIdx); + } + /** Return preceeding visible node in the viewport. */ + _getPrevNodeInView(node, ofs = 1) { + this.visitRows((n) => { + node = n; + if (ofs-- <= 0) { + return false; + } + }, { reverse: true, start: node || this.getActiveNode() }); + return node; + } + /** Return following visible node in the viewport. */ + _getNextNodeInView(node, ofs = 1) { + this.visitRows((n) => { + node = n; + if (ofs-- <= 0) { + return false; + } + }, { reverse: false, start: node || this.getActiveNode() }); + return node; + } + /** + * Append (or insert) a list of toplevel nodes. + * + * @see {@link WunderbaumNode.addChildren} + */ + addChildren(nodeData, options) { + return this.root.addChildren(nodeData, options); + } + /** + * Apply a modification or navigation operation. + * + * Most of these commands simply map to a node or tree method. + * This method is especially useful when implementing keyboard mapping, + * context menus, or external buttons. + * + * Valid commands: + * - 'moveUp', 'moveDown' + * - 'indent', 'outdent' + * - 'remove' + * - 'edit', 'addChild', 'addSibling': (reqires ext-edit extension) + * - 'cut', 'copy', 'paste': (use an internal singleton 'clipboard') + * - 'down', 'first', 'last', 'left', 'parent', 'right', 'up': navigate + * + */ + applyCommand(cmd, nodeOrOpts, options) { + let // clipboard, + node, refNode; + // options = $.extend( + // { setActive: true, clipboard: CLIPBOARD }, + // options_ + // ); + if (nodeOrOpts instanceof WunderbaumNode) { + node = nodeOrOpts; + } + else { + node = this.getActiveNode(); + assert(options === undefined, `Unexpected options: ${options}`); + options = nodeOrOpts; + } + // clipboard = options.clipboard; + switch (cmd) { + // Sorting and indentation: + case "moveUp": + refNode = node.getPrevSibling(); + if (refNode) { + node.moveTo(refNode, "before"); + node.setActive(); + } + break; + case "moveDown": + refNode = node.getNextSibling(); + if (refNode) { + node.moveTo(refNode, "after"); + node.setActive(); + } + break; + case "indent": + refNode = node.getPrevSibling(); + if (refNode) { + node.moveTo(refNode, "appendChild"); + refNode.setExpanded(); + node.setActive(); + } + break; + case "outdent": + if (!node.isTopLevel()) { + node.moveTo(node.getParent(), "after"); + node.setActive(); + } + break; + // Remove: + case "remove": + refNode = node.getPrevSibling() || node.getParent(); + node.remove(); + if (refNode) { + refNode.setActive(); + } + break; + // Add, edit (requires ext-edit): + case "addChild": + this._callMethod("edit.createNode", "prependChild"); + break; + case "addSibling": + this._callMethod("edit.createNode", "after"); + break; + case "rename": + node.startEditTitle(); + break; + // Simple clipboard simulation: + // case "cut": + // clipboard = { mode: cmd, data: node }; + // break; + // case "copy": + // clipboard = { + // mode: cmd, + // data: node.toDict(function(d, n) { + // delete d.key; + // }), + // }; + // break; + // case "clear": + // clipboard = null; + // break; + // case "paste": + // if (clipboard.mode === "cut") { + // // refNode = node.getPrevSibling(); + // clipboard.data.moveTo(node, "child"); + // clipboard.data.setActive(); + // } else if (clipboard.mode === "copy") { + // node.addChildren(clipboard.data).setActive(); + // } + // break; + // Navigation commands: + case "down": + case "first": + case "last": + case "left": + case "pageDown": + case "pageUp": + case "parent": + case "right": + case "up": + return node.navigate(cmd); + default: + error(`Unhandled command: '${cmd}'`); + } + } + /** Delete all nodes. */ + clear() { + this.root.removeChildren(); + this.root.children = null; + this.keyMap.clear(); + this.refKeyMap.clear(); + this.treeRowCount = 0; + this._activeNode = null; + this._focusNode = null; + // this.types = {}; + // this. columns =[]; + // this._columnsById = {}; + // Modification Status + // this.changedSince = 0; + // this.changes.clear(); + // this.changedNodes.clear(); + // // --- FILTER --- + // public filterMode: FilterModeType = null; + // // --- KEYNAV --- + // public activeColIdx = 0; + // public cellNavMode = false; + // public lastQuicksearchTime = 0; + // public lastQuicksearchTerm = ""; + this.update(ChangeType.structure); + } + /** + * Clear nodes and markup and detach events and observers. + * + * This method may be useful to free up resources before re-creating a tree + * on an existing div, for example in unittest suites. + * Note that this Wunderbaum instance becomes unusable afterwards. + */ + destroy() { + this.logInfo("destroy()..."); + this.clear(); + this.resizeObserver.disconnect(); + this.element.innerHTML = ""; + // Remove all event handlers + this.element.outerHTML = this.element.outerHTML; // eslint-disable-line + } + /** + * Return `tree.option.NAME` (also resolving if this is a callback). + * + * See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()} + * to evaluate `node.NAME` setting and `tree.types[node.type].NAME`. + * + * @param name option name (use dot notation to access extension option, e.g. + * `filter.mode`) + */ + getOption(name, defaultValue) { + let ext; + let opts = this.options; + // Lookup `name` in options dict + if (name.indexOf(".") >= 0) { + [ext, name] = name.split("."); + opts = opts[ext]; + } + let value = opts[name]; + // A callback resolver always takes precedence + if (typeof value === "function") { + value = value({ type: "resolve", tree: this }); + } + // Use value from value options dict, fallback do default + // console.info(name, value, opts) + return value !== null && value !== void 0 ? value : defaultValue; + } + /** + * Set tree option. + * Use dot notation to set plugin option, e.g. "filter.mode". + */ + setOption(name, value) { + // this.log(`setOption(${name}, ${value})`); + if (name.indexOf(".") >= 0) { + const parts = name.split("."); + const ext = this.extensions[parts[0]]; + ext.setPluginOption(parts[1], value); + return; + } + this.options[name] = value; + switch (name) { + case "checkbox": + this.update(ChangeType.any); + break; + case "enabled": + this.setEnabled(!!value); + break; + case "fixedCol": + this.element.classList.toggle("wb-fixed-col", !!value); + break; + } + } + /** Return true if the tree (or one of its nodes) has the input focus. */ + hasFocus() { + return this.element.contains(document.activeElement); + } + /** + * Return true if the tree displays a header. Grids have a header unless the + * `header` option is set to `false`. Plain trees have a header if the `header` + * option is a string or `true`. + */ + hasHeader() { + const header = this.options.header; + return this.isGrid() ? header !== false : !!header; + } + /** Run code, but defer rendering of viewport until done. + * + * ``` + * tree.runWithDeferredUpdate(() => { + * return someFuncThatWouldUpdateManyNodes(); + * }); + * ``` + */ + runWithDeferredUpdate(func, hint = null) { + try { + this.enableUpdate(false); + const res = func(); + assert(!(res instanceof Promise), `Promise return not allowed: ${res}`); + return res; + } + finally { + this.enableUpdate(true); + } + } + /** Recursively expand all expandable nodes (triggers lazy load if needed). */ + async expandAll(flag = true, options) { + await this.root.expandAll(flag, options); + } + /** Recursively select all nodes. */ + selectAll(flag = true) { + return this.root.setSelected(flag, { propagateDown: true }); + } + /** Toggle select all nodes. */ + toggleSelect() { + this.selectAll(this.root._anySelectable()); + } + /** + * Return an array of selected nodes. + * @param stopOnParents only return the topmost selected node (useful with selectMode 'hier') + */ + getSelectedNodes(stopOnParents = false) { + return this.root.getSelectedNodes(stopOnParents); + } + /* + * Return an array of selected nodes. + */ + _selectRange(eventInfo) { + this.logDebug("_selectRange", eventInfo); + error("Not yet implemented."); + // const mode = this.options.selectMode!; + // if (mode !== "multi") { + // this.logDebug(`Range selection only available for selectMode 'multi'`); + // return; + // } + // if (eventInfo.canonicalName === "Meta+click") { + // eventInfo.node?.toggleSelected(); + // return false; // don't + // } else if (eventInfo.canonicalName === "Shift+click") { + // let from = this.activeNode; + // let to = eventInfo.node; + // if (!from || !to || from === to) { + // return; + // } + // this.runWithDeferredUpdate(() => { + // this.visitRows( + // (node) => { + // node.setSelected(); + // }, + // { + // includeHidden: true, + // includeSelf: false, + // start: from, + // reverse: from!._rowIdx! > to!._rowIdx!, + // } + // ); + // }); + // return false; + // } + } + /** Return the number of nodes in the data model. + * @param visible if true, nodes that are hidden due to collapsed parents are ignored. + */ + count(visible = false) { + return visible ? this.treeRowCount : this.keyMap.size; + } + /** @internal sanity check. */ + _check() { + let i = 0; + this.visit((n) => { + i++; + }); + if (this.keyMap.size !== i) { + this.logWarn(`_check failed: ${this.keyMap.size} !== ${i}`); + } + // util.assert(this.keyMap.size === i); + } + /** + * Find all nodes that match condition. + * + * @param match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @see {@link WunderbaumNode.findAll} + */ + findAll(match) { + return this.root.findAll(match); + } + /** + * Find all nodes with a given _refKey_ (aka a list of clones). + * + * @param refKey a `node.refKey` value to search for. + * @returns an array of matching nodes with at least two element or `[]` + * if nothing found. + * + * @see {@link WunderbaumNode.getCloneList} + */ + findByRefKey(refKey) { + const clones = this.refKeyMap.get(refKey); + return clones ? Array.from(clones) : []; + } + /** + * Find first node that matches condition. + * + * @param match title string to search for, or a + * callback function that returns `true` if a node is matched. + * @see {@link WunderbaumNode.findFirst} + */ + findFirst(match) { + return this.root.findFirst(match); + } + /** + * Find first node that matches condition. + * + * @see {@link WunderbaumNode.findFirst} + * + */ + findKey(key) { + return this.keyMap.get(key) || null; + } + /** + * Find the next visible node that starts with `match`, starting at `startNode` + * and wrap-around at the end. + * Used by quicksearch and keyboard navigation. + */ + findNextNode(match, startNode) { + //, visibleOnly) { + let res = null; + const firstNode = this.getFirstChild(); + const matcher = typeof match === "string" ? makeNodeTitleStartMatcher(match) : match; + startNode = startNode || firstNode; + function _checkNode(n) { + // console.log("_check " + n) + if (matcher(n)) { + res = n; + } + if (res || n === startNode) { + return false; + } + } + this.visitRows(_checkNode, { + start: startNode, + includeSelf: false, + }); + // Wrap around search + if (!res && startNode !== firstNode) { + this.visitRows(_checkNode, { + start: firstNode, + includeSelf: true, + }); + } + return res; + } + /** + * Find a node relative to another node. + * + * @param node + * @param where 'down', 'first', 'last', 'left', 'parent', 'right', or 'up'. + * (Alternatively the keyCode that would normally trigger this move, + * e.g. `$.ui.keyCode.LEFT` = 'left'. + * @param includeHidden Not yet implemented + */ + findRelatedNode(node, where, includeHidden = false) { + let res = null; + const pageSize = Math.floor(this.listContainerElement.clientHeight / ROW_HEIGHT); + switch (where) { + case "parent": + if (node.parent && node.parent.parent) { + res = node.parent; + } + break; + case "first": + // First visible node + this.visit((n) => { + if (n.isVisible()) { + res = n; + return false; + } + }); + break; + case "last": + this.visit((n) => { + // last visible node + if (n.isVisible()) { + res = n; + } + }); + break; + case "left": + if (node.parent && node.parent.parent) { + res = node.parent; + } + // if (node.expanded) { + // node.setExpanded(false); + // } else if (node.parent && node.parent.parent) { + // res = node.parent; + // } + break; + case "right": + if (node.children && node.children.length) { + res = node.children[0]; + } + // if (this.cellNavMode) { + // throw new Error("Not implemented"); + // } else { + // if (!node.expanded && (node.children || node.lazy)) { + // node.setExpanded(); + // res = node; + // } else if (node.children && node.children.length) { + // res = node.children[0]; + // } + // } + break; + case "up": + res = this._getPrevNodeInView(node); + break; + case "down": + res = this._getNextNodeInView(node); + break; + case "pageDown": + { + const bottomNode = this.getLowestVpNode(); + // this.logDebug(`${where}(${node}) -> ${bottomNode}`); + if (node._rowIdx < bottomNode._rowIdx) { + res = bottomNode; + } + else { + res = this._getNextNodeInView(node, pageSize); + } + } + break; + case "pageUp": + if (node._rowIdx === 0) { + res = node; + } + else { + const topNode = this.getTopmostVpNode(); + // this.logDebug(`${where}(${node}) -> ${topNode}`); + if (node._rowIdx > topNode._rowIdx) { + res = topNode; + } + else { + res = this._getPrevNodeInView(node, pageSize); + } + } + break; + default: + this.logWarn("Unknown relation '" + where + "'."); + } + return res; + } + /** + * Iterator version of {@link Wunderbaum.format}. + */ + *format_iter(name_cb, connectors) { + yield* this.root.format_iter(name_cb, connectors); + } + /** + * Return multiline string representation of the node hierarchy. + * Mostly useful for debugging. + * + * Example: + * ```js + * console.info(tree.format((n)=>n.title)); + * ``` + * logs + * ``` + * Playground + * ├─ Books + * | ├─ Art of War + * | ╰─ Don Quixote + * ├─ Music + * ... + * ``` + * + * @see {@link Wunderbaum.format_iter} and {@link WunderbaumNode.format}. + */ + format(name_cb, connectors) { + return this.root.format(name_cb, connectors); + } + /** + * Return the active cell (`span.wb-col`) of the currently active node or null. + */ + getActiveColElem() { + if (this.activeNode && this.activeColIdx >= 0) { + return this.activeNode.getColElem(this.activeColIdx); + } + return null; + } + /** + * Return the currently active node or null (alias for `tree.activeNode`). + * Alias for {@link Wunderbaum.activeNode}. + * + * @see {@link WunderbaumNode.setActive} + * @see {@link WunderbaumNode.isActive} + * @see {@link Wunderbaum.activeNode} + * @see {@link Wunderbaum.focusNode} + */ + getActiveNode() { + return this.activeNode; + } + /** + * Return the first top level node if any (not the invisible root node). + */ + getFirstChild() { + return this.root.getFirstChild(); + } + /** + * Return the node that currently has keyboard focus or null. + * Alias for {@link Wunderbaum.focusNode}. + * @see {@link WunderbaumNode.setFocus} + * @see {@link WunderbaumNode.hasFocus} + * @see {@link Wunderbaum.activeNode} + * @see {@link Wunderbaum.focusNode} + */ + getFocusNode() { + return this.focusNode; + } + /** Return a {node: WunderbaumNode, region: TYPE} object for a mouse event. + * + * @param {Event} event Mouse event, e.g. click, ... + * @returns {object} Return a {node: WunderbaumNode, region: TYPE} object + * TYPE: 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined + */ + static getEventInfo(event) { + const target = event.target; + const cl = target.classList; + const parentCol = target.closest("span.wb-col"); + const node = Wunderbaum.getNode(target); + const tree = node ? node.tree : Wunderbaum.getTree(event); + const res = { + event: event, + canonicalName: eventToString(event), + tree: tree, + node: node, + region: NodeRegion.unknown, + colDef: undefined, + colIdx: -1, + colId: undefined, + colElem: parentCol, + }; + if (cl.contains("wb-title")) { + res.region = NodeRegion.title; + } + else if (cl.contains("wb-expander")) { + res.region = node.isExpandable() + ? NodeRegion.expander + : NodeRegion.prefix; + } + else if (cl.contains("wb-checkbox")) { + res.region = NodeRegion.checkbox; + } + else if (cl.contains("wb-icon")) { + //|| cl.contains("wb-custom-icon")) { + res.region = NodeRegion.icon; + } + else if (cl.contains("wb-node")) { + res.region = NodeRegion.title; + } + else if (parentCol) { + res.region = NodeRegion.column; + const idx = Array.prototype.indexOf.call(parentCol.parentNode.children, parentCol); + res.colIdx = idx; + } + else if (cl.contains("wb-row")) { + // Plain tree + res.region = NodeRegion.title; + } + else { + // Somewhere near the title + if (event.type !== "mousemove" && !(event instanceof KeyboardEvent)) { + tree === null || tree === void 0 ? void 0 : tree.logWarn("getEventInfo(): not found", event, res); + } + return res; + } + if (res.colIdx === -1) { + res.colIdx = 0; + } + res.colDef = tree === null || tree === void 0 ? void 0 : tree.columns[res.colIdx]; + res.colDef != null ? (res.colId = res.colDef.id) : 0; + // this.log("Event", event, res); + return res; + } + /** + * Return readable string representation for this instance. + * @internal + */ + toString() { + return `Wunderbaum<'${this.id}'>`; + } + /** Return true if any node title or grid cell is currently beeing edited. + * + * See also {@link Wunderbaum.isEditingTitle}. + */ + isEditing() { + const focusElem = this.nodeListElement.querySelector("input:focus,select:focus"); + return !!focusElem; + } + /** Return true if any node is currently in edit-title mode. + * + * See also {@link WunderbaumNode.isEditingTitle} and {@link Wunderbaum.isEditing}. + */ + isEditingTitle() { + return this._callMethod("edit.isEditingTitle"); + } + /** + * Return true if any node is currently beeing loaded, i.e. a Ajax request is pending. + */ + isLoading() { + let res = false; + this.root.visit((n) => { + // also visit rootNode + if (n._isLoading || n._requestId) { + res = true; + return false; + } + }, true); + return res; + } + /** Write to `console.log` with tree name as prefix if opts.debugLevel >= 4. + * @see {@link Wunderbaum.logDebug} + */ + log(...args) { + if (this.options.debugLevel >= 4) { + console.log(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Write to `console.debug` with tree name as prefix if opts.debugLevel >= 4. + * and browser console level includes debug/verbose messages. + * @see {@link Wunderbaum.log} + */ + logDebug(...args) { + if (this.options.debugLevel >= 4) { + console.debug(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Write to `console.error` with tree name as prefix. */ + logError(...args) { + if (this.options.debugLevel >= 1) { + console.error(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** Write to `console.info` with tree name as prefix if opts.debugLevel >= 3. */ + logInfo(...args) { + if (this.options.debugLevel >= 3) { + console.info(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** @internal */ + logTime(label) { + if (this.options.debugLevel >= 4) { + console.time(this + ": " + label); // eslint-disable-line no-console + } + return label; + } + /** @internal */ + logTimeEnd(label) { + if (this.options.debugLevel >= 4) { + console.timeEnd(this + ": " + label); // eslint-disable-line no-console + } + } + /** Write to `console.warn` with tree name as prefix with if opts.debugLevel >= 2. */ + logWarn(...args) { + if (this.options.debugLevel >= 2) { + console.warn(this.toString(), ...args); // eslint-disable-line no-console + } + } + /** + * Make sure that this node is vertically scrolled into the viewport. + * + * Nodes that are above the visible area become the top row, nodes that are + * below the viewport become the bottom row. + */ + scrollTo(nodeOrOpts) { + const PADDING = 2; // leave some pixels between viewport bounds + let node; + let options; + if (nodeOrOpts instanceof WunderbaumNode) { + node = nodeOrOpts; + } + else { + options = nodeOrOpts; + node = options.node; + } + assert(node && node._rowIdx != null, `Invalid node: ${node}`); + const scrollParent = this.element; + const headerHeight = this.headerElement.clientHeight; // May be 0 + const scrollTop = scrollParent.scrollTop; + const vpHeight = scrollParent.clientHeight; + const rowTop = node._rowIdx * ROW_HEIGHT + headerHeight; + const vpTop = headerHeight; + const vpRowTop = rowTop - scrollTop; + const vpRowBottom = vpRowTop + ROW_HEIGHT; + const topNode = options === null || options === void 0 ? void 0 : options.topNode; + // this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts , options); + let newScrollTop = null; + if (vpRowTop >= vpTop) { + if (vpRowBottom <= vpHeight) ; + else { + // Node is below viewport + // this.log("Below viewport"); + newScrollTop = rowTop + ROW_HEIGHT - vpHeight + PADDING; // leave some pixels between viewport bounds + } + } + else { + // Node is above viewport + // this.log("Above viewport"); + newScrollTop = rowTop - vpTop - PADDING; // leave some pixels between viewport bounds + } + if (newScrollTop != null) { + this.log(`scrollTo(${rowTop}): ${scrollTop} => ${newScrollTop}`); + scrollParent.scrollTop = newScrollTop; + if (topNode) { + // Make sure the topNode is always visible + this.scrollTo(topNode); + } + // this.update(ChangeType.scroll); + } + } + /** + * Make sure that this node is horizontally scrolled into the viewport. + * Called by {@link setColumn}. + */ + scrollToHorz() { + // const PADDING = 1; + const fixedWidth = this.columns[0]._widthPx; + const vpWidth = this.element.clientWidth; + const scrollLeft = this.element.scrollLeft; + const colElem = this.getActiveColElem(); + const colLeft = Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.left, 10); + const colRight = colLeft + Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.width, 10); + let newLeft = scrollLeft; + if (colLeft - scrollLeft < fixedWidth) { + // The current column is scrolled behind the left fixed column + newLeft = colLeft - fixedWidth; + } + else if (colRight - scrollLeft > vpWidth) { + // The current column is scrolled outside the right side + newLeft = colRight - vpWidth; + } + newLeft = Math.max(0, newLeft); + // util.assert(node._rowIdx != null); + this.log(`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`); + this.element.scrollLeft = newLeft; + // this.update(ChangeType.scroll); + } + /** + * Set column #colIdx to 'active'. + * + * This higlights the column header and -cells by adding the `wb-active` + * class to all grid cells of the active column.
    + * Available in cell-nav mode only. + * + * If _options.edit_ is true, the embedded input element is focused, or if + * colIdx is 0, the node title is put into edit mode. + */ + setColumn(colIdx, options) { + var _a, _b, _c; + const edit = options === null || options === void 0 ? void 0 : options.edit; + const scroll = (options === null || options === void 0 ? void 0 : options.scrollIntoView) !== false; + assert(this.isCellNav(), "Expected cellNav mode"); + if (typeof colIdx === "string") { + const cid = colIdx; + colIdx = this.columns.findIndex((c) => c.id === colIdx); + assert(colIdx >= 0, `Invalid colId: ${cid}`); + } + assert(0 <= colIdx && colIdx < this.columns.length, `Invalid colIdx: ${colIdx}`); + this.activeColIdx = colIdx; + // Update `wb-active` class for all headers + if (this.hasHeader()) { + for (const rowDiv of this.headerElement.children) { + let i = 0; + for (const colDiv of rowDiv.children) { + colDiv.classList.toggle("wb-active", i++ === colIdx); + } + } + } + (_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.update(ChangeType.status); + // Update `wb-active` class for all cell spans + for (const rowDiv of this.nodeListElement.children) { + let i = 0; + for (const colDiv of rowDiv.children) { + colDiv.classList.toggle("wb-active", i++ === colIdx); + } + } + // Horizontically scroll into view + if (scroll || edit) { + this.scrollToHorz(); + } + if (edit && this.activeNode) { + // this.activeNode.setFocus(); // Blur prev. input if any + if (colIdx === 0) { + this.activeNode.startEditTitle(); + } + else { + (_c = (_b = this.getActiveColElem()) === null || _b === void 0 ? void 0 : _b.querySelector("input,select")) === null || _c === void 0 ? void 0 : _c.focus(); + } + } + } + /* Set or remove keyboard focus to the tree container. @internal */ + _setActiveNode(node) { + this._activeNode = node; + } + /** Set or remove keyboard focus to the tree container. */ + setActiveNode(key, flag = true, options) { + var _a; + (_a = this.findKey(key)) === null || _a === void 0 ? void 0 : _a.setActive(flag, options); + } + /** Set or remove keyboard focus to the tree container. */ + setFocus(flag = true) { + if (flag) { + this.element.focus(); + } + else { + this.element.blur(); + } + } + /* Set or remove keyboard focus to the tree container. @internal */ + _setFocusNode(node) { + this._focusNode = node; + } + update(change, node, options) { + // this.log(`update(${change}) node=${node}`); + if (!(node instanceof WunderbaumNode)) { + options = node; + node = undefined; + } + const immediate = !!getOption(options, "immediate"); + const RF = RenderFlag; + const pending = this.pendingChangeTypes; + if (this._disableUpdateCount) { + // Assuming that we redraw all when enableUpdate() is re-enabled. + // this.log( + // `IGNORED update(${change}) node=${node} (disable level ${this._disableUpdateCount})` + // ); + this._disableUpdateIgnoreCount++; + return; + } + switch (change) { + case ChangeType.any: + case ChangeType.colStructure: + pending.add(RF.header); + pending.add(RF.clearMarkup); + pending.add(RF.redraw); + pending.add(RF.scroll); + break; + case ChangeType.resize: + // case ChangeType.colWidth: + pending.add(RF.header); + pending.add(RF.redraw); + break; + case ChangeType.structure: + pending.add(RF.redraw); + break; + case ChangeType.scroll: + pending.add(RF.scroll); + break; + case ChangeType.row: + case ChangeType.data: + case ChangeType.status: + assert(node, `Option '${change}' requires a node.`); + // Single nodes are immediately updated if already inside the viewport + // (otherwise we can ignore) + if (node._rowElem) { + node._render({ change: change }); + } + break; + default: + error(`Invalid change type '${change}'.`); + } + if (change === ChangeType.colStructure) { + const isGrid = this.isGrid(); + this.element.classList.toggle("wb-grid", isGrid); + if (!isGrid && this.isCellNav()) { + this.setCellNav(false); + } + } + if (pending.size > 0) { + if (immediate) { + this._updateViewportImmediately(); + } + else { + this._updateViewportThrottled(); + } + } + } + /** Disable mouse and keyboard interaction (return prev. state). */ + setEnabled(flag = true) { + const prev = this.enabled; + this.enabled = !!flag; + this.element.classList.toggle("wb-disabled", !flag); + return prev; + } + /** Return false if tree is disabled. */ + isEnabled() { + return this.enabled; + } + /** Return true if tree has more than one column, i.e. has additional data columns. */ + isGrid() { + return this.columns && this.columns.length > 1; + } + /** Return true if cell-navigation mode is active. */ + isCellNav() { + return !!this._cellNavMode; + } + /** Return true if row-navigation mode is active. */ + isRowNav() { + return !this._cellNavMode; + } + /** Set the tree's navigation mode. */ + setCellNav(flag = true) { + var _a; + const prev = this._cellNavMode; + // if (flag === prev) { + // return; + // } + this._cellNavMode = !!flag; + if (flag && !prev) { + // switch from row to cell mode + this.setColumn(0); + } + this.element.classList.toggle("wb-cell-mode", flag); + (_a = this.activeNode) === null || _a === void 0 ? void 0 : _a.update(ChangeType.status); + } + /** Set the tree's navigation mode option. */ + setNavigationOption(mode, reset = false) { + if (!this.isGrid() && mode !== NavModeEnum.row) { + this.logWarn("Plain trees only support row navigation mode."); + return; + } + this.options.navigationModeOption = mode; + switch (mode) { + case NavModeEnum.cell: + this.setCellNav(true); + break; + case NavModeEnum.row: + this.setCellNav(false); + break; + case NavModeEnum.startCell: + if (reset) { + this.setCellNav(true); + } + break; + case NavModeEnum.startRow: + if (reset) { + this.setCellNav(false); + } + break; + default: + error(`Invalid mode '${mode}'.`); + } + } + /** Display tree status (ok, loading, error, noData) using styles and a dummy root node. */ + setStatus(status, options) { + return this.root.setStatus(status, options); + } + /** Add or redefine node type definitions. */ + setTypes(types, replace = true) { + assert(isPlainObject(types), `Expected plain objext: ${types}`); + if (replace) { + this.types = types; + } + else { + extend(this.types, types); + } + // Convert `TYPE.classes` to a Set + for (const t of Object.values(this.types)) { + if (t.classes) { + t.classes = toSet(t.classes); + } + } + } + /** + * Sort nodes list by title or custom criteria. + * @param {function} cmp custom compare function(a, b) that returns -1, 0, or 1 + * (defaults to sorting by title). + * @param {boolean} deep pass true to sort all descendant nodes recursively + */ + sortChildren(cmp = nodeTitleSorter, deep = false) { + this.root.sortChildren(cmp, deep); + } + /** Convert tree to an array of plain objects. + * + * @param callback(dict, node) is called for every node, in order to allow + * modifications. + * Return `false` to ignore this node or `"skip"` to include this node + * without its children. + * @see {@link WunderbaumNode.toDict}. + */ + toDictArray(callback) { + var _a; + const res = this.root.toDict(true, callback); + return (_a = res.children) !== null && _a !== void 0 ? _a : []; + } + /** + * Update column headers and column width. + * Return true if at least one column width changed. + */ + // _updateColumnWidths(options?: UpdateColumnsOptions): boolean { + _updateColumnWidths() { + // options = Object.assign({ updateRows: true, renderMarkup: false }, options); + const defaultMinWidth = 4; + const vpWidth = this.element.clientWidth; + // Shorten last column width to avoid h-scrollbar + // (otherwise resizbing the demo would display a void scrollbar?) + const FIX_ADJUST_LAST_COL = 1; + const columns = this.columns; + const col0 = columns[0]; + let totalWidth = 0; + let totalWeight = 0; + let fixedWidth = 0; + let modified = false; + // this.element.classList.toggle("wb-grid", isGrid); + // if (!isGrid && this.isCellNav()) { + // this.setCellNav(false); + // } + // if (options.calculateCols) { + if (col0.id !== "*") { + throw new Error(`First column must have id '*': got '${col0.id}'.`); + } + // Gather width definitions + this._columnsById = {}; + for (const col of columns) { + this._columnsById[col.id] = col; + const cw = col.width; + if (col.id === "*" && col !== col0) { + throw new Error(`Column id '*' must be defined only once: '${col.title}'.`); + } + if (!cw || cw === "*") { + col._weight = 1.0; + totalWeight += 1.0; + } + else if (typeof cw === "number") { + col._weight = cw; + totalWeight += cw; + } + else if (typeof cw === "string" && cw.endsWith("px")) { + col._weight = 0; + const px = parseFloat(cw.slice(0, -2)); + if (col._widthPx != px) { + modified = true; + col._widthPx = px; + } + fixedWidth += px; + } + else { + error(`Invalid column width: ${cw} (expected string ending with 'px' or number, e.g. "px" or ).`); + } + } + // Share remaining space between non-fixed columns + const restPx = Math.max(0, vpWidth - fixedWidth); + let ofsPx = 0; + for (const col of columns) { + let minWidth; + if (col._weight) { + const cmw = col.minWidth; + if (typeof cmw === "number") { + minWidth = cmw; + } + else if (typeof cmw === "string" && cmw.endsWith("px")) { + minWidth = parseFloat(cmw.slice(0, -2)); + } + else { + minWidth = defaultMinWidth; + } + const px = Math.max(minWidth, (restPx * col._weight) / totalWeight); + if (col._widthPx != px) { + modified = true; + col._widthPx = px; + } + } + col._ofsPx = ofsPx; + ofsPx += col._widthPx; + } + columns[columns.length - 1]._widthPx -= FIX_ADJUST_LAST_COL; + totalWidth = ofsPx - FIX_ADJUST_LAST_COL; + const tw = `${totalWidth}px`; + this.headerElement.style.width = tw; + this.listContainerElement.style.width = tw; + // } + // Every column has now a calculated `_ofsPx` and `_widthPx` + // this.logInfo("UC", this.columns, vpWidth, this.element.clientWidth, this.element); + // console.trace(); + // util.error("BREAK"); + // if (modified) { + // this._renderHeaderMarkup(); + // if (options.renderMarkup) { + // this.update(ChangeType.header, { removeMarkup: true }); + // } else if (options.updateRows) { + // this._updateRows(); + // } + // } + return modified; + } + /** Create/update header markup from `this.columns` definition. + * @internal + */ + _renderHeaderMarkup() { + assert(this.headerElement, "Expected a headerElement"); + const wantHeader = this.hasHeader(); + setElemDisplay(this.headerElement, wantHeader); + if (!wantHeader) { + return; + } + const colCount = this.columns.length; + const headerRow = this.headerElement.querySelector(".wb-row"); + assert(headerRow, "Expected a row in header element"); + headerRow.innerHTML = "".repeat(colCount); + for (let i = 0; i < colCount; i++) { + const col = this.columns[i]; + const colElem = headerRow.children[i]; + colElem.style.left = col._ofsPx + "px"; + colElem.style.width = col._widthPx + "px"; + // Add classes from `columns` definition to `` cells + if (typeof col.headerClasses === "string") { + col.headerClasses + ? colElem.classList.add(...col.headerClasses.split(" ")) + : 0; + } + else { + col.classes ? colElem.classList.add(...col.classes.split(" ")) : 0; + } + const title = escapeHtml(col.title || col.id); + let tooltip = ""; + if (col.tooltip) { + tooltip = escapeTooltip(col.tooltip); + tooltip = ` title="${tooltip}"`; + } + let resizer = ""; + if (i < colCount - 1) { + resizer = ''; + } + colElem.innerHTML = `${title}${resizer}`; + if (this.isCellNav()) { + colElem.classList.toggle("wb-active", i === this.activeColIdx); + } + } + } + /** + * Render pending changes that were scheduled using {@link WunderbaumNode.update} if any. + * + * This is hardly ever neccessary, since we normally either + * - call `update(ChangeType.TYPE)` (async, throttled), or + * - call `update(ChangeType.TYPE, {immediate: true})` (synchronous) + * + * `updatePendingModifications()` will only force immediate execution of + * pending async changes if any. + */ + updatePendingModifications() { + if (this.pendingChangeTypes.size > 0) { + this._updateViewportImmediately(); + } + } + /** + * This is the actual update method, which is wrapped inside a throttle method. + * It calls `updateColumns()` and `_updateRows()`. + * + * This protected method should not be called directly but via + * {@link WunderbaumNode.update}`, {@link Wunderbaum.update}, + * or {@link Wunderbaum.updatePendingModifications}. + * @internal + */ + _updateViewportImmediately() { + var _a; + if (this._disableUpdateCount) { + this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount}).`); + this._disableUpdateIgnoreCount++; + return; + } + if (this._updateViewportThrottled.pending()) { + // this.logWarn(`_updateViewportImmediately() cancel pending timer.`); + this._updateViewportThrottled.cancel(); + } + // Shorten container height to avoid v-scrollbar + const FIX_ADJUST_HEIGHT = 1; + const RF = RenderFlag; + const pending = new Set(this.pendingChangeTypes); + this.pendingChangeTypes.clear(); + const scrollOnly = pending.has(RF.scroll) && pending.size === 1; + if (scrollOnly) { + this._updateRows({ newNodesOnly: true }); + // this.log("_updateViewportImmediately(): scroll only."); + } + else { + this.log("_updateViewportImmediately():", pending); + if (this.options.adjustHeight !== false) { + let height = this.listContainerElement.clientHeight; + const headerHeight = this.headerElement.clientHeight; // May be 0 + const wantHeight = this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT; + if (Math.abs(height - wantHeight) > 1.0) { + // this.log("resize", height, wantHeight); + this.listContainerElement.style.height = wantHeight + "px"; + height = wantHeight; + } + } + // console.profile(`_updateViewportImmediately()`) + if (pending.has(RF.clearMarkup)) { + this.visit((n) => { + n.removeMarkup(); + }); + } + // let widthModified = false; + if (pending.has(RF.header)) { + // widthModified = this._updateColumnWidths(); + this._updateColumnWidths(); + this._renderHeaderMarkup(); + } + this._updateRows(); + // console.profileEnd(`_updateViewportImmediately()`) + } + if (this.options.connectTopBreadcrumb) { + let path = (_a = this.getTopmostVpNode(true)) === null || _a === void 0 ? void 0 : _a.getPath(false, "title", " > "); + path = path ? path + " >" : ""; + this.options.connectTopBreadcrumb.textContent = path; + } + this._callEvent("update"); + } + // /** + // * Assert that TR order matches the natural node order + // * @internal + // */ + // protected _validateRows(): boolean { + // let trs = this.nodeListElement.childNodes; + // let i = 0; + // let prev = -1; + // let ok = true; + // trs.forEach((element) => { + // const tr = element as HTMLTableRowElement; + // const top = Number.parseInt(tr.style.top); + // const n = (tr)._wb_node; + // // if (i < 4) { + // // console.info( + // // `TR#${i}, rowIdx=${n._rowIdx} , top=${top}px: '${n.title}'` + // // ); + // // } + // if (prev >= 0 && top !== prev + ROW_HEIGHT) { + // n.logWarn( + // `TR order mismatch at index ${i}: top=${top}px != ${ + // prev + ROW_HEIGHT + // }` + // ); + // // throw new Error("fault"); + // ok = false; + // } + // prev = top; + // i++; + // }); + // return ok; + // } + /* + * - Traverse all *visible* nodes of the whole tree, i.e. skip collapsed nodes. + * - Store count of rows to `tree.treeRowCount`. + * - Renumber `node._rowIdx` for all visible nodes. + * - Calculate the index range that must be rendered to fill the viewport + * (including upper and lower prefetch) + * - + */ + _updateRows(options) { + // const label = this.logTime("_updateRows"); + // this.log("_updateRows", opts) + options = Object.assign({ newNodesOnly: false }, options); + const newNodesOnly = !!options.newNodesOnly; + const row_height = ROW_HEIGHT; + const vp_height = this.element.clientHeight; + const prefetch = RENDER_MAX_PREFETCH; + // const grace_prefetch = RENDER_MAX_PREFETCH - RENDER_MIN_PREFETCH; + const ofs = this.element.scrollTop; + let startIdx = Math.max(0, ofs / row_height - prefetch); + startIdx = Math.floor(startIdx); + // Make sure start is always even, so the alternating row colors don't + // change when scrolling: + if (startIdx % 2) { + startIdx--; + } + let endIdx = Math.max(0, (ofs + vp_height) / row_height + prefetch); + endIdx = Math.ceil(endIdx); + // this.debug("render", opts); + const obsoleteNodes = new Set(); + this.nodeListElement.childNodes.forEach((elem) => { + const tr = elem; + obsoleteNodes.add(tr._wb_node); + }); + let idx = 0; + let top = 0; + let modified = false; + let prevElem = "first"; + this.visitRows(function (node) { + // node.log("visit") + const rowDiv = node._rowElem; + // Renumber all expanded nodes + if (node._rowIdx !== idx) { + node._rowIdx = idx; + modified = true; + } + if (idx < startIdx || idx > endIdx) { + // row is outside viewport bounds + if (rowDiv) { + prevElem = rowDiv; + } + } + else if (rowDiv && newNodesOnly) { + obsoleteNodes.delete(node); + // no need to update existing node markup + rowDiv.style.top = idx * ROW_HEIGHT + "px"; + prevElem = rowDiv; + } + else { + obsoleteNodes.delete(node); + // Create new markup + if (rowDiv) { + rowDiv.style.top = idx * ROW_HEIGHT + "px"; + } + node._render({ top: top, after: prevElem }); + // node.log("render", top, prevElem, "=>", node._rowElem); + prevElem = node._rowElem; + } + idx++; + top += row_height; + }); + this.treeRowCount = idx; + for (const n of obsoleteNodes) { + n._callEvent("discard"); + n.removeMarkup(); + } + // Resize tree container + this.nodeListElement.style.height = `${top}px`; + // this.log( + // `_updateRows(scrollOfs:${ofs}, ${startIdx}..${endIdx})`, + // this.nodeListElement.style.height + // ); + // this.logTimeEnd(label); + // this._validateRows(); + return modified; + } + /** + * Call `callback(node)` for all nodes in hierarchical order (depth-first, pre-order). + * @see {@link IterableIterator}, {@link WunderbaumNode.visit}. + * + * @param {function} callback the callback function. + * Return false to stop iteration, return "skip" to skip this node and + * children only. + * @returns {boolean} false, if the iterator was stopped. + */ + visit(callback) { + return this.root.visit(callback, false); + } + /** + * Call callback(node) for all nodes in vertical order, top down (or bottom up). + * + * Note that this considers expansion state, i.e. filtered nodes and children + * of collapsed nodes are skipped, unless `includeHidden` is set. + * + * Stop iteration if callback() returns false.
    + * Return false if iteration was stopped. + * + * @returns {boolean} false if iteration was canceled + */ + visitRows(callback, options) { + if (!this.root.hasChildren()) { + return false; + } + if (options && options.reverse) { + delete options.reverse; + return this._visitRowsUp(callback, options); + } + options = options || {}; + let i, nextIdx, parent, res, siblings, stopNode, siblingOfs = 0, skipFirstNode = options.includeSelf === false, node = options.start || this.root.children[0]; + const includeHidden = !!options.includeHidden; + const checkFilter = !includeHidden && this.filterMode === "hide"; + parent = node.parent; + while (parent) { + // visit siblings + siblings = parent.children; + nextIdx = siblings.indexOf(node) + siblingOfs; + assert(nextIdx >= 0, `Could not find ${node} in parent's children: ${parent}`); + for (i = nextIdx; i < siblings.length; i++) { + node = siblings[i]; + if (node === stopNode) { + return false; + } + if (checkFilter && + !node.statusNodeType && + !node.match && + !node.subMatchCount) { + continue; + } + if (!skipFirstNode && callback(node) === false) { + return false; + } + skipFirstNode = false; + // Dive into node's child nodes + if (node.children && + node.children.length && + (includeHidden || node.expanded)) { + res = node.visit((n) => { + if (n === stopNode) { + return false; + } + if (checkFilter && !n.match && !n.subMatchCount) { + return "skip"; + } + if (callback(n) === false) { + return false; + } + if (!includeHidden && n.children && !n.expanded) { + return "skip"; + } + }, false); + if (res === false) { + return false; + } + } + } + // Visit parent nodes (bottom up) + node = parent; + parent = parent.parent; + siblingOfs = 1; // + if (!parent && options.wrap) { + this.logDebug("visitRows(): wrap around"); + assert(options.start, "`wrap` option requires `start`"); + stopNode = options.start; + options.wrap = false; + parent = this.root; + siblingOfs = 0; + } + } + return true; + } + /** + * Call fn(node) for all nodes in vertical order, bottom up. + * @internal + */ + _visitRowsUp(callback, options) { + let children, idx, parent, node = options.start || this.root.children[0]; + const includeHidden = !!options.includeHidden; + if (options.includeSelf !== false) { + if (callback(node) === false) { + return false; + } + } + while (true) { + parent = node.parent; + children = parent.children; + if (children[0] === node) { + // If this is already the first sibling, goto parent + node = parent; + if (!node.parent) { + break; // first node of the tree + } + children = parent.children; + } + else { + // Otherwise, goto prev. sibling + idx = children.indexOf(node); + node = children[idx - 1]; + // If the prev. sibling has children, follow down to last descendant + while ((includeHidden || node.expanded) && + node.children && + node.children.length) { + children = node.children; + parent = node; + node = children[children.length - 1]; + } + } + // Skip invisible + if (!includeHidden && !node.isVisible()) { + continue; + } + if (callback(node) === false) { + return false; + } + } + return true; + } + /** + * Reload the tree with a new source. + * + * Previous data is cleared. Note that also column- and type defintions may + * be passed with the `source` object. + */ + load(source) { + this.clear(); + return this.root.load(source); + } + /** + * Disable render requests during operations that would trigger many updates. + * + * ```js + * try { + * tree.enableUpdate(false); + * // ... (long running operation that would trigger many updates) + * foo(); + * // ... NOTE: make sure that async operations have finished, e.g. + * await foo(); + * } finally { + * tree.enableUpdate(true); + * } + * ``` + */ + enableUpdate(flag) { + /* + 5 7 9 20 25 30 + 1 >-------------------------------------< + 2 >--------------------< + 3 >--------------------------< + */ + if (flag) { + assert(this._disableUpdateCount > 0, "enableUpdate(true) was called too often"); + this._disableUpdateCount--; + // this.logDebug( + // `enableUpdate(${flag}): count -> ${this._disableUpdateCount}...` + // ); + if (this._disableUpdateCount === 0) { + this.logDebug(`enableUpdate(): active again. Re-painting to catch up with ${this._disableUpdateIgnoreCount} ignored update requests...`); + this._disableUpdateIgnoreCount = 0; + this.update(ChangeType.any, { immediate: true }); + } + } + else { + this._disableUpdateCount++; + // this.logDebug( + // `enableUpdate(${flag}): count -> ${this._disableUpdateCount}...` + // ); + // this._disableUpdate = Date.now(); + } + // return !flag; // return previous value + } + /* --------------------------------------------------------------------------- + * FILTER + * -------------------------------------------------------------------------*/ + /** + * Dim or hide nodes. + */ + filterNodes(filter, options) { + return this.extensions.filter.filterNodes(filter, options); + } + /** + * Dim or hide whole branches. + */ + filterBranches(filter, options) { + return this.extensions.filter.filterBranches(filter, options); + } + /** + * Reset the filter. + */ + clearFilter() { + return this.extensions.filter.clearFilter(); + } + /** + * Return true if a filter is currently applied. + */ + isFilterActive() { + return !!this.filterMode; + } + /** + * Re-apply current filter. + */ + updateFilter() { + return this.extensions.filter.updateFilter(); + } + } + Wunderbaum.sequence = 0; + /** Wunderbaum release version number "MAJOR.MINOR.PATCH". */ + Wunderbaum.version = "v0.8.2"; // Set to semver by 'grunt release' + /** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */ + Wunderbaum.util = util; + + exports.Wunderbaum = Wunderbaum; + +})); diff --git a/orochi/static/js/wunderbaum/wunderbaum.umd.min.js b/orochi/static/js/wunderbaum/wunderbaum.umd.min.js new file mode 100644 index 00000000..31185e71 --- /dev/null +++ b/orochi/static/js/wunderbaum/wunderbaum.umd.min.js @@ -0,0 +1,86 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).mar10={})}(this,(function(e){"use strict"; +/*! + * debounce & throttle, taken from https://github.com/lodash/lodash v4.17.21 + * MIT License: https://raw.githubusercontent.com/lodash/lodash/4.17.21-npm/LICENSE + * Modified for TypeScript type annotations. + */const t="object"==typeof global&&null!==global&&global.Object===Object&&global,i="object"==typeof globalThis&&null!==globalThis&&globalThis.Object==Object&&globalThis,s="object"==typeof self&&null!==self&&self.Object===Object&&self,n=i||t||s||Function("return this")();function r(e){const t=typeof e;return null!=e&&("object"===t||"function"===t)}function o(e,t=0,i={}){let s,o,l,a,d,c,h=0,u=!1,p=!1,f=!0;const g=!t&&0!==t&&"function"==typeof n.requestAnimationFrame;if("function"!=typeof e)throw new TypeError("Expected a function");function v(t){const i=s,n=o;return s=o=void 0,h=t,a=e.apply(n,i),a}function m(e,t){return g?(n.cancelAnimationFrame(d),n.requestAnimationFrame(e)):setTimeout(e,t)}function y(e){const i=e-c;return void 0===c||i>=t||i<0||p&&e-h>=l}function b(){const e=Date.now();if(y(e))return w(e);d=m(b,function(e){const i=e-h,s=t-(e-c);return p?Math.min(s,l-i):s}(e))}function w(e){return d=void 0,f&&s?v(e):(s=o=void 0,a)}function E(...e){const i=Date.now(),n=y(i);if(s=e,o=this,c=i,n){if(void 0===d)return function(e){return h=e,d=m(b,t),u?v(e):a}(c);if(p)return d=m(b,t),v(c)}return void 0===d&&(d=m(b,t)),a}return t=+t||0,r(i)&&(u=!!i.leading,p="maxWait"in i,l=p?Math.max(+i.maxWait||0,t):l,f="trailing"in i?!!i.trailing:f),E.cancel=function(){void 0!==d&&function(e){if(g)return n.cancelAnimationFrame(e);clearTimeout(e)}(d),h=0,s=c=o=d=void 0},E.flush=function(){return void 0===d?a:w(Date.now())},E.pending=function(){return void 0!==d},E}function l(e,t=0,i={}){let s=!0,n=!0;if("function"!=typeof e)throw new TypeError("Expected a function");return r(i)&&(s="leading"in i?!!i.leading:s,n="trailing"in i?!!i.trailing:n),o(e,t,{leading:s,trailing:n,maxWait:t})} +/*! + * Wunderbaum - util + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */const a={0:"",1:"left",2:"middle",3:"right",4:"back",5:"forward"},d=function(){const e=navigator;return{isMac:/Mac/.test(e.platform)}}().isMac,c=/[&<>"'/]/g,h=/[<>"'/]/g,u={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};class p extends Error{constructor(e){super(e),this.name="ValidationError"}}function f(e,t){if(!e)throw t=t||"Assertion failed.",new Error(t)}function g(e){"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()}function v(e){throw new Error(e)}function m(e){return(""+e).replace(c,(function(e){return u[e]}))}function y(e){return(""+e).replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}function b(e){return(""+e).replace(h,(function(e){return u[e]}))}function w(e,t=!1){const i=e.tagName;let s=null;if("SPAN"===i&&e.classList.contains("wb-col")){const i=e,n=i.querySelector("input,select");if(n)return w(n,t);i.innerText=""+s}else if("INPUT"===i){const i=e;switch(i.type){case"button":case"reset":case"submit":case"image":break;case"checkbox":s=i.indeterminate?null:i.checked;break;case"date":case"datetime":case"datetime-local":case"month":case"time":case"week":s=t?i.valueAsDate:i.value;break;case"number":case"range":s=i.valueAsNumber;break;case"radio":{const e=i.name,t=i.parentElement.querySelector(`input[name="${e}"]:checked`);s=t?t.value:void 0}break;default:s=i.value}}else if("SELECT"===i){s=e.value}return s}function E(e,t){const i=k(e).style;t?"none"===i.display&&(i.display=""):""===i.display&&(i.display="none")}function _(e){const t=document.createElement("template");return t.innerHTML=e.trim(),t.content.firstElementChild}const x=new Set(["Alt","Control","Meta","Shift"]);function k(e){return e?"string"==typeof e?document.querySelector(e):e:null}function C(e){const t=e.key,i=e.type,s=[];return e.altKey&&s.push("Alt"),e.ctrlKey&&s.push("Control"),e.metaKey&&s.push("Meta"),e.shiftKey&&s.push("Shift"),"click"===i||"dblclick"===i?s.push(a[e.button]+i):"wheel"===i?s.push(i):x.has(t)||s.push(t),s.join("+")}function N(...e){for(let t=1;t{e.addEventListener(t,(function(e){if(!n)return r(e);if(e.target){let t=e.target;if(t.matches(n))return r(e);if(t=t.closest(n),t)return r(e)}}))}))}function I(e,t,i,s){let n,r;const o=s||e,l=e[t],a=(...e)=>l.apply(o,e),d=e=>l.apply(o,e);e[t]=(...e)=>{try{return n=o._super,r=o._superApply,o._super=a,o._superApply=d,i.apply(o,e)}finally{o._super=n,o._superApply=r}}}function M(e,t,i=void 0){let s;e&&t.indexOf(".")>=0&&([s,t]=t.split("."),e=e[s]);const n=e?e[t]:null;return null!=n?n:i}function A(e){if(e instanceof Set)return e;if("string"==typeof e){const t=new Set;for(const i of e.split(" "))t.add(i.trim());return t}if(Array.isArray(e))return new Set(e);throw new Error("Cannot convert to Set: "+e)}function O(e,t){const i=Object.assign({minDelay:16,defaultDelay:200,maxDelay:5e3,delayFactor:2},t),s=Math.max(16,+i.minDelay),n=+i.maxDelay;let r=0,o=null,l=null;const a=(...t)=>{if(r)o=t,r+=1;else{r=1;const d=t;o=null;const c=Date.now();try{e.apply(this,d)}catch(e){console.error(e)}const h=Date.now()-c,u=Math.min(Math.max(s,h*i.delayFactor),n),p=Math.max(s,u-h);l=setTimeout((()=>{l=null,r=0,null!=o&&a.apply(this,o)}),p)}};return a.cancel=()=>{l&&(clearTimeout(l),l=null),o=null,r=0},a.pending=()=>!!l,a.flush=()=>{throw new Error("Not implemented")},a}var $,P,R,F,z,U=Object.freeze({__proto__:null,Deferred:class{constructor(){this.thens=[],this.catches=[],this.status=""}resolve(e){if(this.status)throw new Error("already settled");this.status="resolved",this.resolvedValue=e,this.thens.forEach((t=>t(e))),this.thens=[]}reject(e){if(this.status)throw new Error("already settled");this.status="rejected",this.rejectedError=e,this.catches.forEach((t=>t(e))),this.catches=[]}then(e){"resolved"===status?e(this.resolvedValue):this.thens.unshift(e)}catch(e){"rejected"===this.status?e(this.rejectedError):this.catches.unshift(e)}promise(){return{then:this.then,catch:this.catch}}},MAX_INT:9007199254740991,MOUSE_BUTTONS:a,ValidationError:p,adaptiveThrottle:O,assert:f,debounce:o,documentReady:g,documentReadyPromise:function(){return new Promise((e=>{g(e)}))},each:function(e,t){if(null==e)return e;const i=e.length;let s=0;if("number"==typeof i)for(;s")>=0&&v("Not implemented"),e},getOption:M,getValueFromElem:w,isArray:S,isEmptyObject:D,isFunction:function(e){return"function"==typeof e},isMac:d,isPlainObject:T,noop:function(...e){},onEvent:L,overrideMethod:I,setElemDisplay:E,setTimeoutPromise:function(e,t){return new Promise(((i,s)=>{setTimeout((()=>{try{i(e.apply(this))}catch(e){s(e)}}),t)}))},setValueToElem:function e(t,i){const s=t.tagName;if("SPAN"===s&&t.classList.contains("wb-col")){const s=t,n=s.querySelector("input,select");if(n)return e(n,i);s.innerText=""+i}else if("INPUT"===s){const e=t,s=e.type;switch(s){case"checkbox":e.indeterminate=null===i,e.checked=!!i;break;case"date":case"month":case"time":case"week":case"datetime":case"datetime-local":e.valueAsDate=new Date(i);break;case"number":case"range":null==i?e.value=i:e.valueAsNumber=i;break;case"radio":v(`Not yet implemented: ${s}`);break;case"button":case"reset":case"submit":case"image":break;default:e.value=null!=i?i:""}}else if("SELECT"===s){const e=t;null==i?e.selectedIndex=-1:e.value=i}},sleep:async function(e){return new Promise((t=>setTimeout(t,e)))},throttle:l,toSet:A,toggleCheckbox:function(e,t,i){const s=k(e);if(f("checkbox"===s.type,`Expected a checkbox: ${s.type}`),null!=i||(i=s.classList.contains("wb-tristate")||s.indeterminate),void 0===t){switch(s.indeterminate?null:s.checked){case!0:t=!1;break;case!1:t=!i||null;break;case null:t=!0}}s.indeterminate=null==t,s.checked=!!t},type:function(e){return Object.prototype.toString.call(e).replace(/^\[object (.+)\]$/,"$1").toLowerCase()}}); +/*! + * Wunderbaum - types + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */!function(e){e.any="any",e.data="data",e.colStructure="colStructure",e.resize="resize",e.row="row",e.structure="structure",e.status="status",e.scroll="scroll"}($||($={})),function(e){e.clearMarkup="clearMarkup",e.header="header",e.redraw="redraw",e.scroll="scroll"}(P||(P={})),function(e){e.ok="ok",e.loading="loading",e.error="error",e.noData="noData",e.paging="paging"}(R||(R={})),function(e){e.unknown="",e.checkbox="checkbox",e.column="column",e.expander="expander",e.icon="icon",e.prefix="prefix",e.title="title"}(F||(F={})),function(e){e.startRow="startRow",e.cell="cell",e.startCell="startCell",e.row="row"}(z||(z={})); +/*! + * Wunderbaum - wb_extension_base + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */ +class V{constructor(e,t,i){this.enabled=!0,this.tree=e,this.id=t,this.treeOpts=e.options;const s=e.options;void 0===this.treeOpts[t]?s[t]=this.extensionOpts=N({},i):(this.extensionOpts=N({},i,s[t]),s[t]=this.extensionOpts),this.enabled=this.getPluginOption("enabled",!0)}init(){this.tree.element.classList.add("wb-ext-"+this.id)}getPluginOption(e,t){var i;return null!==(i=this.extensionOpts[e])&&void 0!==i?i:t}setPluginOption(e,t){this.extensionOpts[e]=t}setEnabled(e=!0){return this.setPluginOption("enabled",!!e)}onKeyEvent(e){}onRender(e){}} +/*! + * Wunderbaum - ext-filter + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */const q="￷",j="￸",K=new RegExp(y("￷"),"g"),H=new RegExp(y("￸"),"g");class W extends V{constructor(e){super(e,"filter",{connectInput:null,autoApply:!0,autoExpand:!1,counter:!0,fuzzy:!1,hideExpandedCounter:!0,hideExpanders:!1,highlight:!0,leavesOnly:!1,mode:"dim",noData:!0}),this.lastFilterArgs=null}init(){super.init();const e=this.getPluginOption("connectInput");e&&(this.queryInput=k(e),L(this.queryInput,"input",o((e=>{this.filterNodes(this.queryInput.value.trim(),{})}),700)))}setPluginOption(e,t){if(super.setPluginOption(e,t),"mode"===e)this.tree.filterMode="hide"===t?"hide":"dim",this.tree.updateFilter()}_applyFilterNoUpdate(e,t,i){return this.tree.runWithDeferredUpdate((()=>this._applyFilterImpl(e,t,i)))}_applyFilterImpl(e,t,i){let s,n,r=0;const o=Date.now(),l=this.tree,a=l.options,d=a.autoCollapse,c=N({},a.filter,i),h="hide"===c.mode,u=!!c.leavesOnly&&!t;if("string"==typeof e){if(""===e)return l.logInfo("Passing an empty string as a filter is handled as clearFilter()."),void this.clearFilter();s=c.fuzzy?e.split("").map(y).reduce((function(e,t){return e+"([^"+t+"]*)"+t}),""):y(e);const t=new RegExp(s,"i"),i=new RegExp(y(e),"gi");e=e=>{if(!e.title)return!1;const s=e.title,r=s.match(t);return r&&c.highlight&&(n=c.fuzzy?function(e,t,i=!0){const s=[];for(let e=1;e"+n[e]+""}));return n.join("")} +/*! + * Wunderbaum - ext-keynav + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */(s,r,!0):s.replace(i,(function(e){return q+e+j})),e.titleWithHighlight=m(n).replace(K,"").replace(H,"")),!!r}}return l.filterMode=c.mode,this.lastFilterArgs=arguments,l.element.classList.toggle("wb-ext-filter-hide",!!h),l.element.classList.toggle("wb-ext-filter-dim",!h),l.element.classList.toggle("wb-ext-filter-hide-expanders",!!c.hideExpanders),l.root.subMatchCount=0,l.visit((e=>{delete e.match,delete e.titleWithHighlight,e.subMatchCount=0})),l.setStatus(R.ok),a.autoCollapse=!1,l.visit((i=>{if(u&&null!=i.children)return;let s=e(i);if("skip"===s)return i.visit((function(e){e.match=!1}),!0),"skip";let n=!1;(t||"branch"===s)&&i.parent.match&&(s=!0,n=!0),s&&(r++,i.match=!0,i.visitParents((e=>{e!==i&&(e.subMatchCount+=1),!c.autoExpand||n||e.expanded||(e.setExpanded(!0,{noAnimation:!0,noEvents:!0}),e._filterAutoExpanded=!0)}),!0))})),a.autoCollapse=d,0===r&&c.noData&&h&&("string"==typeof c.noData?l.root.setStatus(R.noData,{message:c.noData}):l.root.setStatus(R.noData)),l.logInfo(`Filter '${s}' found ${r} nodes in ${Date.now()-o} ms.`),r}filterNodes(e,t){return this._applyFilterNoUpdate(e,!1,t)}filterBranches(e,t){return this._applyFilterNoUpdate(e,!0,t)}updateFilter(){var e;const t=this.tree;t.filterMode&&this.lastFilterArgs&&(null===(e=t.options.filter)||void 0===e?void 0:e.autoApply)?this._applyFilterNoUpdate.apply(this,this.lastFilterArgs):t.logWarn("updateFilter(): no filter active.")}clearFilter(){const e=this.tree;e.enableUpdate(!1),e.setStatus(R.ok),delete e.root.match,delete e.root.subMatchCount,e.visit((e=>{delete e.match,delete e.subMatchCount,delete e.titleWithHighlight,e._filterAutoExpanded&&e.expanded&&e.setExpanded(!1,{noAnimation:!0,noEvents:!0}),delete e._filterAutoExpanded})),e.filterMode=null,this.lastFilterArgs=null,e.element.classList.remove("wb-ext-filter-dim","wb-ext-filter-hide"),e.enableUpdate(!0)}}class B extends V{constructor(e){super(e,"keynav",{})}_getEmbeddedInputElem(e){var t;let i=null;if(e&&null!=e.type)i=e;else{const e=null===(t=this.tree.getActiveColElem())||void 0===t?void 0:t.querySelector("input,select");e&&(i=e)}return i}_isCurInputFocused(){var e;return!!(null===(e=this.tree.getActiveColElem())||void 0===e?void 0:e.querySelector("input:focus,select:focus"))}onKeyEvent(e){const t=e.event,i=this.tree,s=e.options,n=!t.ctrlKey||s.autoActivate,r=this._getEmbeddedInputElem(t.target),o=r&&this._isCurInputFocused(),l=s.navigationModeOption;let a,d=C(t),c=e.node,h=!0;if(!i.isEnabled())return!1;if(!1===i._callEvent("keydown",e))return!1;if(!1===i._callMethod("edit._preprocessKeyEvent",e))return!1;if(!c){const e=i.getFocusNode()||i.getActiveNode(),t=i.getFirstChild();if(!e&&t&&"ArrowDown"===d)return t.logInfo("Keydown: activate first node."),void t.setActive();a=e||t,a&&(a.setFocus(),c=i.getFocusNode(),c.logInfo("Keydown: force focus on active node."))}const u=c.isColspan();if(i.isRowNav()){if(o){switch(d){case"Enter":r.blur(),i.setFocus();break;case"Escape":c._render(),i.setFocus()}return}if(s.quicksearch&&1===d.length&&/^\w$/.test(d)&&!r){const e=Date.now();e-i.lastQuicksearchTime>500&&(i.lastQuicksearchTerm=""),i.lastQuicksearchTime=e,i.lastQuicksearchTerm+=d;const s=i.findNextNode(i.lastQuicksearchTerm,i.getActiveNode());return s&&s.setActive(!0,{event:t}),void t.preventDefault()}switch(d){case"Enter":c.isActive()&&(c.isExpanded()?d="Subtract":c.isExpandable(!0)&&(d="Add"));break;case"ArrowLeft":c.expanded&&(d="Subtract");break;case"ArrowRight":if(!c.expanded&&c.isExpandable(!0))d="Add";else if(l===z.startCell||l===z.startRow)return t.preventDefault(),i.setCellNav(),!1}switch(d){case"+":case"Add":c.setExpanded(!0);break;case"-":case"Subtract":c.setExpanded(!1);break;case" ":c.getOption("checkbox")?c.toggleSelected():c.setActive(!0,{event:t});break;case"Enter":c.setActive(!0,{event:t});break;case"ArrowDown":case"ArrowLeft":case"ArrowRight":case"ArrowUp":case"Backspace":case"End":case"Home":case"Control+End":case"Control+Home":case"Meta+ArrowDown":case"Meta+ArrowUp":case"PageDown":case"PageUp":c.navigate(d,{activate:n,event:t});break;default:h=!1}}else{const e=r?r.type||r.tagName:"",s=r&&"checkbox"!==e;if(o){if("Escape"===d)return c.logDebug("Reset focused input on Escape"),r.setCustomValidity(""),c._render(),i.setFocus(),void i.setColumn(i.activeColIdx);if("Enter"!==d)return r&&r.checkValidity&&!r.checkValidity()?(c.logDebug(`Ignored ${d} inside invalid input`),!1):void c.logDebug(`Ignored ${d} inside focused input`)}else if(r&&1===d.length&&s)return r.focus(),r.value="",c.logDebug(`Focus input: ${d}`),!1;switch("Tab"===d?(d="ArrowRight",h=!0):"Shift+Tab"===d&&(d=i.activeColIdx>0?"ArrowLeft":"",h=!0),d){case"+":case"Add":c.setExpanded(!0);break;case"-":case"Subtract":c.setExpanded(!1);break;case" ":0===i.activeColIdx&&c.getOption("checkbox")?(c.toggleSelected(),h=!0):r&&"checkbox"===e&&(r.click(),h=!0);break;case"F2":r&&!o&&s&&(r.focus(),h=!0);break;case"Enter":i.setFocus(),(0===i.activeColIdx||u)&&c.isExpandable()?(c.setExpanded(!c.isExpanded()),h=!0):r&&!o&&s&&(r.focus(),h=!0);break;case"Escape":i.setFocus(),c.log("keynav: focus tree..."),i.isCellNav()&&l!==z.cell&&(c.log("keynav: setCellNav(false)"),i.setCellNav(!1),i.setFocus(),h=!0);break;case"ArrowLeft":i.setFocus(),u&&c.isExpanded()?c.setExpanded(!1):!u&&i.activeColIdx>0?i.setColumn(i.activeColIdx-1):l!==z.cell&&i.setCellNav(!1),h=!0;break;case"ArrowRight":i.setFocus(),u&&!c.isExpanded()?c.setExpanded():!u&&i.activeColIdx0&&i.setColumn(0),h=!0;break;case"End":i.setFocus(),!u&&i.activeColIdx=4){const t=this.ignoreEvents,i=this.prefix;I(e,"callEvent",(function(s,n){if(t.has(s))return e._superApply(arguments);const r=Date.now(),o=e._superApply(arguments);return e.logDebug(`${i}: callEvent('${s}') took ${Date.now()-r} ms.`,arguments[1]),o}))}}onKeyEvent(e){this.tree.logDebug(`${this.prefix}: onKeyEvent()`,e)}} +/*! + * Wunderbaum - common + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */const Q=22,Y=new RegExp(/\.|\//),J={bootstrap:{error:"bi bi-exclamation-triangle",loading:"bi bi-chevron-right wb-busy",noData:"bi bi-question-circle",expanderExpanded:"bi bi-chevron-down",expanderCollapsed:"bi bi-chevron-right",expanderLazy:"bi bi-chevron-right wb-helper-lazy-expander",checkChecked:"bi bi-check-square",checkUnchecked:"bi bi-square",checkUnknown:"bi bi-dash-square-dotted",radioChecked:"bi bi-circle-fill",radioUnchecked:"bi bi-circle",radioUnknown:"bi bi-record-circle",folder:"bi bi-folder2",folderOpen:"bi bi-folder2-open",folderLazy:"bi bi-folder-symlink",doc:"bi bi-file-earmark"},fontawesome6:{error:"fa-solid fa-triangle-exclamation",loading:"fa-solid fa-chevron-right fa-beat",noData:"fa-solid fa-circle-question",expanderExpanded:"fa-solid fa-chevron-down",expanderCollapsed:"fa-solid fa-chevron-right",expanderLazy:"fa-solid fa-chevron-right wb-helper-lazy-expander",checkChecked:"fa-regular fa-square-check",checkUnchecked:"fa-regular fa-square",checkUnknown:"fa-regular fa-square-minus",radioChecked:"fa-solid fa-circle",radioUnchecked:"fa-regular fa-circle",radioUnknown:"fa-regular fa-circle-question",folder:"fa-solid fa-folder-closed",folderOpen:"fa-regular fa-folder-open",folderLazy:"fa-solid fa-folder-plus",doc:"fa-regular fa-file"}},X=new Set(["_format","_keyMap","_positional","_typeList","_valueMap","_version","children","columns","types"]),Z={" ":"toggleSelect","+":"expand",Add:"expand",ArrowDown:"down",ArrowLeft:"left",ArrowRight:"right",ArrowUp:"up",Backspace:"parent","/":"collapseAll",Divide:"collapseAll",End:"lastCol",Home:"firstCol","Control+End":"last","Control+Home":"first","Meta+ArrowDown":"last","Meta+ArrowUp":"first","*":"expandAll",Multiply:"expandAll",PageDown:"pageDown",PageUp:"pageUp","-":"collapse",Subtract:"collapse"};function ee(e){return e instanceof RegExp?function(t){return e.test(t.title)}:(f("string"==typeof e,`Expected a string or RegExp: ${e}`),function(t){return t.title===e})}function te(e,t){const i=e.title.toLowerCase(),s=t.title.toLowerCase();return i===s?0:i>s?1:-1}function ie(e){let{_format:t,_version:i=1,_keyMap:s,_valueMap:n}=e;f(1===i,`Expected file version 1 instead of ${i}`);let r=s,o={};if(r)for(const[e,t]of Object.entries(r))o[t]=e;if(r&&r.t){const e="source._keyMap maps from long to short since v0.7.0. Flip key/value!";console.warn(e),[r,o]=[o,r]}if(null!=e._typeList){const t='source._typeList is deprecated since v0.7.0: use source._valueMap: {"type": [...]} instead.';if(null!=n)throw new Error(t);console.warn(t),n={type:e._typeList},delete e._typeList}"flat"===t&&function(e){var t,i,s;const{_format:n,_keyMap:r={},_positional:o=[],children:l}=e;if("flat"!==n)throw new Error(`Expected source._format: "flat", but got ${n}`);if(o&&o.includes("children"))throw new Error(`source._positional must not include "children": ${o}`);let a=r;if(r.t){const e="source._keyMap maps from long to short since v0.7.0. Flip key/value!";console.warn(e),a={};for(const[e,t]of Object.entries(r))a[t]=e}const d=o.map((e=>a[e])),c=[],h={},u={},p=null!==(t=a.key)&&void 0!==t?t:"key",f=null!==(i=a.children)&&void 0!==i?i:"children";for(const[e,t]of l.entries()){const[i,n,r={}]=t;t[1]=null,null!=t[2]&&(t[2]=null),n.forEach(((e,t)=>{r[d[t]]=e})),u[e]=r;const o=r[p];null!=o&&(h[o]=r);let l=null;if(null===i);else if("number"==typeof i){if(l=u[i],void 0===l)throw new Error(`unflattenSource: Could not find parent node by index: ${i}.`)}else if(l=h[i],void 0===l)throw new Error(`unflattenSource: Could not find parent node by key: ${i}`);l?(null!==(s=l[f])&&void 0!==s||(l[f]=[]),l[f].push(r)):c.push(r)}e.children=c}(e),delete e._format,delete e._version,delete e._keyMap,delete e._valueMap,delete e._positional,(s||n)&&function e(t){for(const i of t)Object.getOwnPropertyNames(i).forEach((e=>{const t=i[e];let r=e;if(s&&null!=o[e]&&(r=o[e],r!==e&&(i[r]=t,delete i[e])),n&&"number"==typeof t&&null!=n[r]){const e=n[r][t];if(null==e)throw new Error(`Expected valueMap[${r}][${t}] entry in [${n[r]}]`);i[r]=e}})),i.children&&e(i.children)}(e.children)} +/*! + * Wunderbaum - ext-dnd + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */const se="application/x-wunderbaum-node";class ne extends V{constructor(e){super(e,"dnd",{autoExpandMS:1500,multiSource:!1,effectAllowed:"all",dropEffectDefault:"move",guessDropEffect:!0,preventForeignNodes:!1,preventLazyParents:!0,preventNonNodes:!1,preventRecursion:!0,preventSameParent:!1,preventVoidMoves:!0,serializeClipboardData:!0,scroll:!0,scrollSensitivity:20,scrollSpeed:5,sourceCopyHook:null,dragStart:null,drag:null,dragEnd:null,dragEnter:null,dragOver:null,dragExpand:null,drop:null,dragLeave:null}),this.srcNode=null,this.lastTargetNode=null,this.lastEnterStamp=0,this.lastAllowedDropRegions=null,this.lastDropEffect=null,this.lastDropRegion=!1,this.currentScrollDir=0,this.applyScrollDirThrottled=l(this._applyScrollDir,50)}init(){super.init();const e=this.tree,t=e.options.dnd;t.dragStart&&L(e.element,"dragstart drag dragend",this.onDragEvent.bind(this)),t.dragEnter&&L(e.element,"dragenter dragover dragleave drop",this.onDropEvent.bind(this))}_leaveNode(){const e=this.lastTargetNode;this.lastEnterStamp=0,e&&(e.setClass("wb-drop-target wb-drop-over wb-drop-after wb-drop-before",!1),this.lastTargetNode=null)}unifyDragover(e){if(!1===e)return!1;if(e instanceof Set)return e.size>0&&e;if(!0===e)return new Set(["over","before","after"]);if("string"==typeof e||S(e))return(e=A(e)).size>0&&e;throw new Error("Unsupported drop region definition: "+e)}_calcDropRegion(e,t){const i=e.offsetY;return!!t&&(3===t.size?i<5.5?"before":i>16.5?"after":"over":1===t.size&&t.has("over")?"over":i>11?"after":"before")}_guessDropEffect(e){var t;const i=this.treeOpts.dnd,s=null!==(t=i.effectAllowed)&&void 0!==t?t:"all",n=["all","copy","copyLink","copyMove"].includes(s),r=["all","link","copyLink","linkMove"].includes(s),o=["all","move","copyMove","linkMove"].includes(s);let l=i.dropEffectDefault;return i.guessDropEffect&&(d?(e.altKey&&n&&(l="copy"),e.metaKey&&o&&(l="move"),e.altKey&&e.metaKey&&r&&(l="link")):(e.ctrlKey&&n&&(l="copy"),e.shiftKey&&o&&(l="move"),e.altKey&&r&&(l="link"))),l}_isVoidDrop(e,t,i){return!(!this.treeOpts.dnd.preventVoidMoves||!t)&&("before"===i&&e===t.getNextSibling()||"after"===i&&e===t.getPrevSibling()||(t===e||t.parent===e))}_applyScrollDir(){if(this.isDragging()&&this.currentScrollDir){const e=this.tree.options.dnd,t=this.tree.element,i=t.scrollTop;this.currentScrollDir<0?t.scrollTop=Math.max(0,i-e.scrollSpeed):this.currentScrollDir>0&&(t.scrollTop=i+e.scrollSpeed)}}_autoScroll(e){const t=this.tree,i=t.options.dnd.scrollSensitivity,s=t.element,n=t.headerElement.clientHeight,r=s.offsetHeight,o=s.scrollTop;return this.currentScrollDir=0,o>0&&e>0&&e<=i+n?this.currentScrollDir=-1:o=r-i&&(this.currentScrollDir=1),this.currentScrollDir&&this.applyScrollDirThrottled(),s.scrollTop-o}isDragging(){return!!this.srcNode}onDragEvent(e){var t;const i=this.treeOpts.dnd,s=pe.getNode(e);if(s){if(["dragstart","dragend"].includes(e.type)&&this.tree.logDebug(`onDragEvent.${e.type} srcNode: ${s}`,e),"dragstart"===e.type){if(e.dataTransfer.effectAllowed=i.effectAllowed,s.isEditingTitle())return s.logDebug("Prevented dragging node in edit mode."),e.preventDefault(),!1;if(!s._callEvent("dnd.dragStart",{event:e}))return e.preventDefault(),!1;const n=s.toDict(!0,(e=>{e._orgKey=e.key,delete e.key}));n._treeId=s.tree.id,i.serializeClipboardData&&("function"==typeof i.serializeClipboardData?e.dataTransfer.setData(se,i.serializeClipboardData(n,s)):e.dataTransfer.setData(se,JSON.stringify(n))),(null===(t=e.dataTransfer)||void 0===t?void 0:t.types.includes("text/plain"))||e.dataTransfer.setData("text/plain",s.title),this.srcNode=s,setTimeout((()=>{s.setClass("wb-drag-source")}),0)}else"drag"===e.type?i.drag&&s._callEvent("dnd.drag",{event:e}):"dragend"===e.type&&(s.setClass("wb-drag-source",!1),this.srcNode=null,this.lastTargetNode&&this._leaveNode(),s._callEvent("dnd.dragEnd",{event:e}));return!0}this.tree.logWarn(`onDragEvent.${e.type}: no node`)}onDropEvent(e){var t;const i=this.srcNode,s=i?i.tree:null,n=pe.getNode(e),r=this.treeOpts.dnd,o=e.dataTransfer,l=this._calcDropRegion(e,this.lastAllowedDropRegions),a=(e,t)=>(e&&this.tree.log(`Prevented drop operation (${t}).`),e);if(n){if(["drop"].includes(e.type)&&this.tree.logDebug(`onDropEvent.${e.type} targetNode: ${n}, ea: ${null==o?void 0:o.effectAllowed}, de: ${null==o?void 0:o.dropEffect}, cy: ${e.offsetY}, r: ${l}, srcNode: ${i}`,e),"dragenter"===e.type){if(this.lastAllowedDropRegions=null,this.lastTargetNode&&this.lastTargetNode!==n&&this._leaveNode(),this.lastTargetNode=n,this.lastEnterStamp=Date.now(),a(n.isStatusNode(),"is status node")||a(r.preventForeignNodes&&n.tree!==s,"preventForeignNodes")||a(r.preventLazyParents&&!n.isLoaded(),"preventLazyParents")||a(r.preventNonNodes&&!i,"preventNonNodes")||a(r.preventRecursion&&(null==i?void 0:i.isAncestorOf(n)),"preventRecursion")||a(r.preventSameParent&&i&&n.parent===i.parent,"preventSameParent")||a(r.preventVoidMoves&&n===i,"preventVoidMoves"))return o.dropEffect="none",!0;o.dropEffect=this._guessDropEffect(e)||"none";let t=n._callEvent("dnd.dragEnter",{event:e,sourceNode:i});return t=this.unifyDragover(t),t?(this.lastAllowedDropRegions=t,this.lastDropEffect=o.dropEffect,n.setClass("wb-drop-target"),e.preventDefault(),!1):(o.dropEffect="none",!0)}if("dragover"===e.type){const t=e.clientY-this.tree.element.offsetTop;this._autoScroll(t),o.dropEffect=this._guessDropEffect(e)||"none",n._callEvent("dnd.dragOver",{event:e,sourceNode:i});const s=this._calcDropRegion(e,this.lastAllowedDropRegions);if(this.lastDropRegion=s,this.lastDropEffect=o.dropEffect,r.autoExpandMS>0&&n.isExpandable(!0)&&!n._isLoading&&Date.now()-this.lastEnterStamp>r.autoExpandMS&&!1!==n._callEvent("dnd.dragExpand",{event:e,sourceNode:i})&&n.setExpanded(),!s||this._isVoidDrop(n,i,s))return;return n.setClass("wb-drop-over","over"===s),n.setClass("wb-drop-before","before"===s),n.setClass("wb-drop-after","after"===s),e.preventDefault(),!1}if("dragleave"===e.type)n._callEvent("dnd.dragLeave",{event:e,sourceNode:i});else if("drop"===e.type){e.stopPropagation(),e.preventDefault(),this._leaveNode();const i=this.lastDropRegion;let s=null===(t=e.dataTransfer)||void 0===t?void 0:t.getData(se);s=s?JSON.parse(s):null;const r=this.srcNode,o=this.lastDropEffect;setTimeout((()=>{n._callEvent("dnd.drop",{event:e,region:i,suggestedDropMode:"over"===i?"appendChild":i,suggestedDropEffect:o,sourceNode:r,sourceNodeData:s})}),10)}return!1}this._leaveNode()}} +/*! + * Wunderbaum - drag_observer + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */class re{constructor(e){if(this.start={x:0,y:0,altKey:!1,ctrlKey:!1,metaKey:!1,shiftKey:!1},this.dragElem=null,this.dragging=!1,this.events=["mousedown","mouseup","mousemove","keydown"],!e.root)throw new Error("Missing `root` option.");this.opts=Object.assign({thresh:5},e),this.root=e.root,this._handler=this.handleEvent.bind(this),this.events.forEach((e=>{this.root.addEventListener(e,this._handler)}))}disconnect(){this.events.forEach((e=>{this.root.removeEventListener(e,this._handler)}))}getDragElem(){return this.dragElem}isDragging(){return this.dragging}stopDrag(e){this.dragging&&this.opts.dragstop&&e&&(e.type="dragstop",this.opts.dragstop(e)),this.dragElem=null,this.dragging=!1}handleEvent(e){const t=e.type,i=this.opts,s={type:e.type,event:e,dragElem:this.dragElem,dx:e.pageX-this.start.x,dy:e.pageY-this.start.y,apply:void 0};switch(t){case"keydown":this.stopDrag(s);break;case"mousedown":if(this.dragElem){this.stopDrag(s);break}if(i.selector){let t=e.target;if(t.matches(i.selector))this.dragElem=t;else{if(t=t.closest(i.selector),!t)break;this.dragElem=t}}this.start.x=e.pageX,this.start.y=e.pageY,this.start.altKey=e.altKey,this.start.ctrlKey=e.ctrlKey,this.start.metaKey=e.metaKey,this.start.shiftKey=e.shiftKey;break;case"mousemove":if(!this.dragElem)break;if(!this.dragging){if(i.thresh){if(s.dx*s.dx+s.dy*s.dythis.tree.element.contains(e.dragElem),drag:e=>this.handleDrag(e),dragstop:e=>this.handleDrag(e)})}init(){super.init()}handleDrag(e){const t=pe.getEventInfo(e.event);this.tree.log(`${e.type}(${e.dx})`,e,t)}} +/*! + * Wunderbaum - deferred + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */class le{constructor(){this._promise=new Promise(((e,t)=>{this._resolve=e,this._reject=t}))}resolve(e){this._resolve(e)}reject(e){this._reject(e)}promise(){return this._promise}then(e){return this._promise.then(e)}catch(e){return this._promise.catch(e)}finally(e){return this._promise.finally(e)}} +/*! + * Wunderbaum - wunderbaum_node + * Copyright (c) 2021-2023, Martin Wendt. Released under the MIT license. + * v0.8.2, Sat, 17 Feb 2024 07:32:06 GMT (https://github.com/mar10/wunderbaum) + */const ae=new Set(["checkbox","classes","expanded","icon","iconTooltip","key","lazy","_partsel","radiogroup","refKey","selected","statusNodeType","title","tooltip","type","unselectable"]),de=new Set(ae);de.delete("_partsel"),de.delete("unselectable");class ce{constructor(e,t,i){var s,n;this.refKey=void 0,this.children=null,this.classes=null,this.data={},this._isLoading=!1,this._requestId=0,this._errorInfo=null,this._partsel=!1,this._partload=!1,this.subMatchCount=0,this._rowIdx=0,this._rowElem=void 0,f(!t||t.tree===e,`Invalid parent: ${t}`),f(!i.children,"'children' not allowed here"),this.tree=e,this.parent=t,this.key=""+(null!==(s=i.key)&&void 0!==s?s:++ce.sequence),this.title=""+(null!==(n=i.title)&&void 0!==n?n:"<"+this.key+">"),null!=i.refKey&&(this.refKey=""+i.refKey),null!=i.type&&(this.type=""+i.type),this.expanded=!0===i.expanded,null!=i.icon&&(this.icon=i.icon),this.lazy=!0===i.lazy,null!=i.statusNodeType&&(this.statusNodeType=""+i.statusNodeType),null!=i.colspan&&(this.colspan=!!i.colspan),null!=i.checkbox&&(this.checkbox=!!i.checkbox),null!=i.radiogroup&&(this.radiogroup=!!i.radiogroup),this.selected=!0===i.selected,!0===i.unselectable&&(this.unselectable=!0),i.classes&&this.setClass(i.classes);for(const[e,t]of Object.entries(i))ae.has(e)||(this.data[e]=t);t&&!this.statusNodeType&&e._registerNode(this)}toString(){return`WunderbaumNode@${this.key}<'${this.title}'>`}*[Symbol.iterator](){const e=this.children;if(e)for(let t=0,i=e.length;t=0,`options.before must be a direct child of ${this}`),this.children.splice(e,0,...o)}else this.children=o;i.update($.structure)}finally{i.enableUpdate(!0)}return o[0]}addNode(e,t="appendChild"){switch("over"===t&&(t="appendChild"),t){case"after":return this.parent.addChildren(e,{before:this.getNextSibling()});case"before":return this.parent.addChildren(e,{before:this});case"prependChild":return this.addChildren(e,{before:0});case"appendChild":return this.addChildren(e)}f(!1,`Invalid mode: ${t}`)}applyCommand(e,t){return this.tree.applyCommand(e,this,t)}collapseSiblings(e){for(const t of this.parent.children)t!==this&&t.expanded&&t.setExpanded(!1,e)}setClass(e,t=!0){const i=A(e);if(t)null===this.classes&&(this.classes=new Set),i.forEach((e=>{var i;this.classes.add(e),null===(i=this._rowElem)||void 0===i||i.classList.toggle(e,t)}));else{if(null===this.classes)return;i.forEach((e=>{var i;this.classes.delete(e),null===(i=this._rowElem)||void 0===i||i.classList.toggle(e,t)})),0===this.classes.size&&(this.classes=null)}}startEditTitle(){this.tree._callMethod("edit.startEditTitle",this)}async expandAll(e=!0,t){const i=this.tree,s=this.tree.options.minExpandLevel,{depth:n=99,loadLazy:r,force:o,keepActiveNodeVisible:l=!0}=null!=t?t:{},a={scrollIntoView:!1,force:o,loadLazy:r};const d=i.logTime(`${this}.expandAll(${e})`);try{i.enableUpdate(!1),await async function t(i,n){var l;if(0===n)return;const d=null==n?null:n-1,c=[];return null===(l=i.children)||void 0===l||l.forEach((i=>{if(e)if(!i.expanded&&(i.children||r&&i.lazy)){const e=i.setExpanded(!0,a);c.push(e),e.then((async()=>{await t(i,d)}))}else c.push(t(i,d));else(!s||o||i.getLevel()>s)&&i.setExpanded(!1,a),t(i,d)})),new Promise((e=>{Promise.all(c).then((()=>{e(!0)}))}))}(this,n)}finally{i.enableUpdate(!0),i.logTimeEnd(d)}i.activeNode&&l&&i.activeNode.scrollIntoView()}findAll(e){const t="function"==typeof e?e:ee(e),i=[];return this.visit((e=>{t(e)&&i.push(e)})),i}findDirectChild(e){const t=this.children;if(!t)return null;if("string"==typeof e){for(let i=0,s=t.length;i{if(t(e))return i=e,!1})),i}findRelatedNode(e,t=!1){return this.tree.findRelatedNode(this,e,t)}*format_iter(e,t){function i(e){const t=e.parent.children;return e===t[t.length-1]}null!=t||(t=[" "," | "," ╰─ "," ├─ "]),null!=e||(e=e=>""+e);const s=s=>{const n=[e(s)];n.unshift(t[i(s)?2:3]);let r=s.parent;for(;r&&r!==this;)n.unshift(t[i(r)?0:1]),r=r.parent;return n.join("")};yield e(this);for(const e of this)yield s(e)}format(e,t){const i=[];for(const s of this.format_iter(e,t))i.push(s);return i.join("\n")}getColElem(e){var t;"string"==typeof e&&(e=this.tree.columns.findIndex((t=>t.id===e)));const i=null===(t=this._rowElem)||void 0===t?void 0:t.querySelectorAll("span.wb-col");return i?i[e]:null}getCloneList(e=!1){if(!this.refKey)return[];const t=this.tree.findByRefKey(this.refKey);return e?t:[...t].filter((e=>e!==this))}getFirstChild(){return this.children?this.children[0]:null}getLastChild(){return this.children?this.children[this.children.length-1]:null}getLevel(){let e=0,t=this.parent;for(;t;)e++,t=t.parent;return e}getNextSibling(){const e=this.parent.children,t=e.indexOf(this);return e[t+1]||null}getParent(){return this.parent}getParentList(e=!1,t=!1){const i=[];let s=t?this:this.parent;for(;s;)(e||s.parent)&&i.unshift(s),s=s.parent;return i}getPath(e=!0,t="title",i="/"){let s;const n=[],r="function"==typeof t;return this.visitParents((e=>{e.parent&&(s=r?t(e):e[t],n.unshift(s))}),e),n.join(i)}getPrevSibling(){const e=this.parent.children,t=e.indexOf(this);return e[t-1]||null}hasChildren(){if(this.lazy){if(null==this.children)return;if(0===this.children.length)return!1;if(1===this.children.length&&this.children[0].isStatusNode())return;return!0}return!(!this.children||!this.children.length)}hasClass(e){return!!this.classes&&this.classes.has(e)}isActive(){return this.tree.activeNode===this}isAncestorOf(e){return e&&e.isDescendantOf(this)}isChildOf(e){return e&&this.parent===e}isClone(){return!!this.refKey&&this.tree.findByRefKey(this.refKey).length>1}isColspan(){return!!this.getOption("colspan")}isDescendantOf(e){if(!e||e.tree!==this.tree)return!1;let t=this.parent;for(;t;){if(t===e)return!0;t===t.parent&&v(`Recursive parent link: ${t}`),t=t.parent}return!1}isExpandable(e=!1){return!(e&&this.expanded||!1===this.children)&&(null==this.children?!!this.lazy:0!==this.children.length||!!this.tree.options.emptyChildListExpandable)}isEditingTitle(){return this.tree._callMethod("edit.isEditingTitle",this)}isExpanded(){return!!this.expanded}isFirstSibling(){const e=this.parent;return!e||e.children[0]===this}isLastSibling(){const e=this.parent;return!e||e.children[e.children.length-1]===this}isLazy(){return!!this.lazy}isLoaded(){return!this.lazy||void 0!==this.hasChildren()}isLoading(){return this._isLoading}isPagingNode(){return"paging"===this.statusNodeType}isParentOf(e){return e&&e.parent===this}isPartload(){return!!this._partload}isPartsel(){return!this.selected&&!!this._partsel}isRadio(){return!!this.parent.radiogroup||"radio"===this.getOption("checkbox")}isRendered(){return!!this._rowElem}isRootNode(){return this.tree.root===this}isSelected(){return!!this.selected||!!this._partsel&&void 0}isStatusNode(){return!!this.statusNodeType}isTopLevel(){return this.tree.root===this.parent}isUnloaded(){return void 0===this.hasChildren()}isVisible(){const e="hide"===this.tree.filterMode,t=this.getParentList(!1,!1);if(e&&!this.match&&!this.subMatchCount)return!1;for(let e=0,i=t.length;ei)return void this.logWarn(`Ignored load response #${i} because #${this._requestId} is pending.`);if(this.logDebug(`Received response for load request #${i}`),null===this.parent&&null!==s)return void this.logWarn("Lazy parent node was removed while loading: discarding response.");this.setStatus(R.ok);const r=Date.now();this._loadSourceObject(t),l=Date.now()-r}else{if("function"==typeof e.then){const i=t.logTime(`Resolve thenable ${e}`);e=await Promise.resolve(e),t.logTimeEnd(i)}this._loadSourceObject(e),l=Date.now()-n}}catch(t){throw this.logError("Error during load()",e,t),this._callEvent("error",{error:t}),this.setStatus(R.error,{message:""+t}),t}finally{this._requestId=0,r=Date.now()-n,t.options.debugLevel>=3&&t.logInfo(`Load source took ${r/1e3} seconds (transfer: ${o/1e3}s, processing: ${l/1e3}s)`)}}async loadLazy(e=!1){const t=this.expanded;if(f(this.lazy,"load() requires a lazy node"),e||this.isUnloaded())if(this.isLoading())this.logWarn("loadLazy() called while already loading: ignored.");else{this.isLoaded()&&this.resetLazy(),this.setStatus(R.loading);try{const e=await this._callEvent("lazyLoad");if(!1===e)return void this.setStatus(R.ok);f(S(e)||e&&e.url,"The lazyLoad event must return a node list, `{url: ...}`, or false."),await this.load(e),this.setStatus(R.ok),t?(this.expanded=!0,this.tree.update($.structure)):this.update()}catch(e){this.logError("Error during loadLazy()",e),this._callEvent("error",{error:e}),this.setStatus(R.error,{message:""+e})}}}log(...e){this.tree.options.debugLevel>=4&&console.log(this.toString(),...e)}logDebug(...e){this.tree.options.debugLevel>=4&&console.debug(this.toString(),...e)}logError(...e){this.tree.options.debugLevel>=1&&console.error(this.toString(),...e)}logInfo(...e){this.tree.options.debugLevel>=3&&console.info(this.toString(),...e)}logWarn(...e){this.tree.options.debugLevel>=2&&console.warn(this.toString(),...e)}async makeVisible(e){let t;const i=new le,s=[],n=this.getParentList(!1,!1),r=n.length,o=M(e,"noAnimation",!1),l=M(e,"scrollIntoView",!0);for(t=r-1;t>=0;t--){const e={noAnimation:o};s.push(n[t].setExpanded(!0,e))}return Promise.all(s).then((()=>{l&&this.tree?(this.tree.updatePendingModifications(),this.scrollIntoView().then((()=>{i.resolve()}))):i.resolve()})),i.promise()}moveTo(e,t="appendChild",i){let s;"over"===t&&(t="appendChild"),"prependChild"===t&&(e.children&&e.children.length?(t="before",e=e.children[0]):t="appendChild");const n=this.tree,r=this.parent,o="appendChild"===t?e:e.parent;if(this!==e){if(this.parent?o.isDescendantOf(this)&&v("Cannot move a node to its own descendant"):v("Cannot move system root"),o!==r&&r.triggerModifyChild("remove",this),1===this.parent.children.length){if(this.parent===o)return;this.parent.children=this.parent.lazy?[]:null,this.parent.expanded=!1}else s=this.parent.children.indexOf(this),f(s>=0,"invalid source parent"),this.parent.children.splice(s,1);if(this.parent=o,o.hasChildren())switch(t){case"appendChild":o.children.push(this);break;case"before":s=o.children.indexOf(e),f(s>=0,"invalid target parent"),o.children.splice(s,0,this);break;case"after":s=o.children.indexOf(e),f(s>=0,"invalid target parent"),o.children.splice(s+1,0,this);break;default:v(`Invalid mode '${t}'.`)}else o.children=[this];i&&e.visit(i,!0),o===r?o.triggerModifyChild("move",this):o.triggerModifyChild("add",this),n!==e.tree&&(this.logWarn("Cross-tree moveTo is experimental!"),this.visit((t=>{t.tree=e.tree}),!0)),setTimeout((()=>{n.update($.any)}),0)}}async navigate(e,t){e=Z[e]||e;const i=this.findRelatedNode(e);if(!i)return this.logWarn(`Could not find related node '${e}'.`),Promise.resolve(this);try{i.makeVisible({scrollIntoView:!1})}catch(e){}return i.setFocus(),!1===(null==t?void 0:t.activate)?Promise.resolve(this):i.setActive(!0,{event:null==t?void 0:t.event})}remove(){const e=this.tree,t=this.parent.children.indexOf(this);this.triggerModify("remove"),this.parent.children.splice(t,1),this.visit((t=>{t.removeMarkup(),e._unregisterNode(t)}),!0),e.update($.structure)}removeChildren(){var e,t;const i=this.tree;this.children&&((null===(e=i.activeNode)||void 0===e?void 0:e.isDescendantOf(this))&&i.activeNode.setActive(!1),(null===(t=i.focusNode)||void 0===t?void 0:t.isDescendantOf(this))&&i._setFocusNode(null),this.triggerModifyChild("remove",null),this.visit((e=>{i._unregisterNode(e)})),this.lazy?this.children=[]:this.children=null,this.isRootNode()||(this.expanded=!1),this.tree.update($.structure))}removeMarkup(){this._rowElem&&(delete this._rowElem._wb_node,this._rowElem.remove(),this._rowElem=void 0)}_getRenderInfo(){const e={},t={},i=this.isColspan(),s=this._rowElem?this._rowElem.querySelectorAll("span.wb-col"):null;let n=0;for(const r of this.tree.columns)e[r.id]={id:r.id,idx:n,elem:s?s[n]:null,info:r},i||"*"===r.id||(t[r.id]=e[r.id]),n++;return{allColInfosById:e,renderColInfosById:t}}_createIcon(e,t,i,s){let n,r=this.getOption("icon");if(this._errorInfo?r=e.error:this._isLoading&&s&&(r=e.loading),!1===r)return null;"string"==typeof r||(r=this.statusNodeType?e[this.statusNodeType]:this.expanded?e.folderOpen:this.children?e.folder:this.lazy?e.folderLazy:e.doc),r?r.indexOf("<")>=0?n=_(r):Y.test(r)?n=_(``):(n=document.createElement("i"),n.className="wb-icon "+r):(n=document.createElement("i"),n.className="wb-icon"),i?t.replaceChild(n,i):t.appendChild(n);const o=this._callEvent("iconBadge",{iconSpan:n});let l=null;if(null!=o&&!1!==o){let e="",t="";T(o)?(l=""+o.badge,e=o.badgeClass?" "+o.badgeClass:"",t=o.badgeTooltip?` title="${o.badgeTooltip}"`:""):l="number"==typeof o?""+o:o,"string"==typeof l&&(l=_(`${m(l)}`)),l&&n.append(l)}return n}_render_markup(e){const t=this.tree,i=t.options,s=this.getOption("checkbox"),n=t.columns,r=this.getLevel(),o=t.isRowNav()?null:t.activeColIdx;let l,a=this._rowElem,d=null,c=null;const h=!a;f(h,"Expected unrendered node"),f(!h||e&&e.after,"opts.after expected, unless updating"),f(!this.isRootNode(),"Root node not allowed"),a=document.createElement("div"),a.classList.add("wb-row"),a.style.top=this._rowIdx*Q+"px",this._rowElem=a,a._wb_node=this;const u=document.createElement("span");u.classList.add("wb-node","wb-col"),a.appendChild(u);let p=0;s&&(d=document.createElement("i"),d.classList.add("wb-checkbox"),("radio"===s||this.parent.radiogroup)&&d.classList.add("wb-radio"),u.appendChild(d),p+=20);for(let e=r-1;e>0;e--)l=document.createElement("i"),l.classList.add("wb-indent"),u.appendChild(l),p+=20;(!i.minExpandLevel||r>i.minExpandLevel)&&(c=document.createElement("i"),c.classList.add("wb-expander"),u.appendChild(c),p+=20);this._createIcon(t.iconMap,u,null,!c)&&(p+=20);const g=document.createElement("span");g.classList.add("wb-title"),u.appendChild(g),u._ofsTitlePx=p,t.options.dnd.dragStart&&(u.draggable=!0);if(!this.isColspan()&&n.length>1){let e=0;for(const t of n){let i;e++,"*"===t.id?i=u:(i=document.createElement("span"),i.classList.add("wb-col"),a.appendChild(i)),e===o&&i.classList.add("wb-active"),t.classes&&i.classList.add(...t.classes.split(" ")),i.style.left=t._ofsPx+"px",i.style.width=t._widthPx+"px",h&&t.html&&"string"==typeof t.html&&(i.innerHTML=t.html)}}switch(e?e.after:"last"){case"first":t.nodeListElement.prepend(a);break;case"last":t.nodeListElement.appendChild(a);break;default:e.after.after(a)}e.isNew=!0,this._render_data(e)}_render_data(e){f(this._rowElem,"No _rowElem");const t=this.tree,i=t.options,s=this._rowElem,n=!!e.isNew,r=!!e.preventScroll,o=t.columns,l=this.isColspan(),a=s.querySelector("span.wb-node"),d=a.querySelector("span.wb-title"),c=t.element.scrollTop;if(this.titleWithHighlight?d.innerHTML=this.titleWithHighlight:d.textContent=this.title,r&&(t.element.scrollTop=c),!i.skeleton)if(l){const e=t.element.clientWidth;d.style.width=e-a._ofsTitlePx-7+"px"}else d.style.width=o[0]._widthPx-a._ofsTitlePx-7+"px";if(e.isDataChange=!0,this._render_status(e),this.statusNodeType)this._callEvent("renderStatusNode",{isNew:n,nodeElem:a,isColspan:l});else if(this.parent){const e=this._getRenderInfo();this._callEvent("render",{isNew:n,nodeElem:a,isColspan:l,allColInfosById:e.allColInfosById,renderColInfosById:e.renderColInfosById})}}_render_status(e){const t=this.tree,i=t.iconMap,s=t.options,n=this.type?t.types[this.type]:null,r=this._rowElem,o=r.querySelector("span.wb-node"),l=o.querySelector("i.wb-expander"),a=o.querySelector("i.wb-checkbox"),d=["wb-row"];if(this.expanded&&d.push("wb-expanded"),this.lazy&&d.push("wb-lazy"),this.selected&&d.push("wb-selected"),this._partsel&&d.push("wb-partsel"),this===t.activeNode&&d.push("wb-active"),this===t.focusNode&&d.push("wb-focus"),this._errorInfo&&d.push("wb-error"),this._isLoading&&d.push("wb-loading"),this.isColspan()&&d.push("wb-colspan"),this.statusNodeType&&d.push("wb-status-"+this.statusNodeType),this.match&&d.push("wb-match"),this.subMatchCount&&d.push("wb-submatch"),s.skeleton&&d.push("wb-skeleton"),r.className=d.join(" "),this.classes&&r.classList.add(...this.classes),n&&n.classes&&r.classList.add(...n.classes),l){let e=null;this._isLoading?e=i.loading:this.isExpandable(!1)?e=this.expanded?i.expanderExpanded:i.expanderCollapsed:this.lazy&&null==this.children&&(e=i.expanderLazy),null==e?l.classList.add("wb-indent"):Y.test(e)?l.style.backgroundImage=`url('${e}')`:l.className="wb-expander "+e}if(a){let e="wb-checkbox ";this.isRadio()?(e+="wb-radio ",this.selected?e+=i.radioChecked:e+=i.radioUnchecked):this.selected?e+=i.checkChecked:this._partsel?e+=i.checkUnknown:e+=i.checkUnchecked,a.className=e}if(!e.isNew){let e=0;for(const i of r.children)i.classList.toggle("wb-active",e++===t.activeColIdx),i.classList.remove("wb-error","wb-invalid");const i=o.querySelector("i.wb-icon");i&&this._createIcon(t.iconMap,o,i,!l)}if(!1!==e.resizeCols&&!this.isColspan()){const e=r.querySelectorAll("span.wb-col");let t=0,i=0;for(const s of this.tree.columns){const n=e[t];n.style.left=`${i}px`,n.style.width=`${s._widthPx}px`,t++,i+=s._widthPx}}}_render(e){const t=Object.assign({change:$.data},e);switch(this._rowElem||(t.change=$.row),t.change){case"status":this._render_status(t);break;case"data":this._render_data(t);break;case"row":this._render_markup(t);break;default:v(`Invalid change type '${t.change}'.`)}}resetLazy(){this.removeChildren(),this.expanded=!1,this.lazy=!0,this.children=null,this.tree.update($.structure)}toDict(e=!1,t){const i={};if(de.forEach((e=>{const t=this[e];t instanceof Set?t.size&&(i[e]=Array.prototype.join.call(t.keys()," ")):(t||!1===t||0===t)&&(i[e]=t)})),D(this.data)||(i.data=N({},this.data),D(i.data)&&delete i.data),t){const s=t(i,this);if(!1===s)return!1;"skip"===s&&(e=!1)}if(e&&S(this.children)){i.children=[];for(let e=0,s=this.children.length;e=0&&([s,e]=e.split("."));const n=s[e];if("function"==typeof n){const e=n.call(i,{type:"resolve",tree:i,node:this});if(void 0!==e)return e}if(void 0!==this[e])return this[e];const r=this.type?i.types[this.type]:void 0,o=r?r[e]:void 0;return void 0!==o?o:null!=n?n:t}async scrollIntoView(e){const t=Object.assign({node:this},e);return this.tree.scrollTo(t)}async setActive(e=!0,t){const i=this.tree,s=i.getActiveNode(),n=null==t?void 0:t.retrigger,r=null==t?void 0:t.focusTree,o=null==t?void 0:t.noEvents,l=null==t?void 0:t.event,a=null==t?void 0:t.colIdx,d=null==t?void 0:t.edit;if(f(!a||i.isCellNav(),"colIdx requires cellNav"),f(!d||null!=a,"edit requires colIdx"),!o)if(e){if(s!==this||n){if(!1===(null==s?void 0:s._callEvent("deactivate",{nextNode:this,event:l}))||!1===this._callEvent("beforeActivate",{prevNode:s,event:l}))return;i._setActiveNode(null),null==s||s.update($.status)}}else(s===this||n)&&this._callEvent("deactivate",{nextNode:null,event:l});return s!==this&&(e&&i._setActiveNode(this),null==s||s.update($.status),this.update($.status)),this.makeVisible().then((()=>{e&&((r||d)&&(i.setFocus(),i._setFocusNode(this),i.focusNode.setFocus()),null!=a&&i.isCellNav()&&i.setColumn(a,{edit:d}),o||this._callEvent("activate",{prevNode:s,event:l}))}))}async setExpanded(e=!0,t){const{force:i,scrollIntoView:s,immediate:n}=null!=t?t:{},r=!(null==t?void 0:t.noEvents);if(!e&&this.isExpanded()&&this.getLevel()<=this.tree.getOption("minExpandLevel")&&!i)return void this.logDebug("Ignored collapse request below minExpandLevel.");if(!e==!this.expanded)return;if(r&&!1===this._callEvent("beforeExpand",{flag:e}))return;e&&this.getOption("autoCollapse")&&this.collapseSiblings(t),e&&this.lazy&&null==this.children&&await this.loadLazy(),this.expanded=e;const o={immediate:n};if(this.tree.update($.structure,o),e&&s){const e=this.getLastChild();e&&(this.tree.updatePendingModifications(),e.scrollIntoView({topNode:this}))}r&&this._callEvent("expand",{flag:e})}setFocus(e=!0){f(!!e,"Blur is not yet implemented");const t=this.tree.focusNode;this.tree._setFocusNode(this),null==t||t.update(),this.update()}setIcon(e){this.icon=e,this.update()}setKey(e,t){throw new Error("Not yet implemented")}update(e=$.data){f(e===$.status||e===$.data,`Invalid change type ${e}`),this.tree.update(e,this)}getSelectedNodes(e=!1){const t=[];return this.visit((i=>{if(i.selected&&(t.push(i),!0===e))return"skip"})),t}toggleSelected(e){let t=this.isSelected();return t=void 0!==t||this.isRadio()?!t:this._anySelectable(),this.setSelected(t,e)}_anySelectable(){let e=!1;return this.visit((t=>{if(!1===t.selected&&!t.unselectable&&!t.hasChildren()&&!t.parent.radiogroup)return e=!0,!1})),e}_changeSelectStatusProps(e){let t=!1;switch(e){case!1:t=this.selected||this._partsel,this.selected=!1,this._partsel=!1;break;case!0:t=!this.selected||!this._partsel,this.selected=!0,this._partsel=!0;break;case void 0:t=this.selected||!this._partsel,this.selected=!1,this._partsel=!0;break;default:v(`Invalid state: ${e}`)}return t&&this.update(),t}fixSelection3AfterClick(e){const t=!!(null==e?void 0:e.force),i=this.isSelected();this.visit((e=>{if(e.radiogroup)return"skip";!t&&e.getOption("unselectable")||e._changeSelectStatusProps(i)})),this.fixSelection3FromEndNodes()}fixSelection3FromEndNodes(e){const t=!!(null==e?void 0:e.force);f("hier"===this.tree.options.selectMode,"expected selectMode 'hier'");const i=e=>{let s;const n=e.children;if(n&&n.length){let e=!0,t=!1;for(let s=0,r=n.length;s{let t;const i=e.children;let s=!0,n=!1;for(let e=0,r=i.length;e{this.visit((t=>{t.setSelected(e)}))})),n):(e===n||s&&!1===this._callEvent("beforeSelect",{flag:e})||(i.runWithDeferredUpdate((()=>{if(r){if(!e&&!(null==t?void 0:t.force))return n;for(const e of this.parent.children)e.selected=e===this}else this.selected=e,"hier"===o?this.fixSelection3AfterClick():"single"===o&&i.visit((e=>{e.selected=!1}))})),s&&this._callEvent("select",{flag:e})),n):n}setStatus(e,t){const i=this.tree,s=null==t?void 0:t.message,n=null==t?void 0:t.details;let r=null;const o=e=>{const t=this.children,s=t?t[0]:null;return f(e.statusNodeType,"Not a status node"),f(!s||!s.isStatusNode(),"Child must not be a status node"),r=this.addNode(e,"prependChild"),r.match=!0,i.update($.structure),r};switch((()=>{const e=this.children;e&&e.length&&e[0].isStatusNode()&&e[0].remove()})(),e){case"ok":this._isLoading=!1,this._errorInfo=null;break;case"loading":this._isLoading=!0,this._errorInfo=null,this.parent?this.update($.status):o({statusNodeType:e,title:i.options.strings.loading+(s?" ("+s+")":""),checkbox:!1,colspan:!0,tooltip:n});break;case"error":o({statusNodeType:e,title:i.options.strings.loadError+(s?" ("+s+")":""),checkbox:!1,colspan:!0,tooltip:n}),this._isLoading=!1,this._errorInfo={message:s,details:n};break;case"noData":o({statusNodeType:e,title:s||i.options.strings.noData,checkbox:!1,colspan:!0,tooltip:n}),this._isLoading=!1,this._errorInfo=null;break;default:v("invalid node status "+e)}return i.update($.structure),r}setTitle(e){this.title=e,this.update()}_sortChildren(e,t){const i=this.children;if(i&&(i.sort(e),t))for(let s=0,n=i.length;s{const r=t._callEvent(e,n);Promise.resolve(r).then((e=>{i(e)})).catch((e=>{s(e)}))})).then((e=>{if(!s.checkValidity())throw t.logWarn("inputElem.checkValidity() failed: throwing...."),new p(s.validationMessage);return e})).catch((n=>{if(!(n instanceof p))throw t.logError(`Error in ${e} event handler (throw e.util.ValidationError instead if this was intended)`,n),i.classList.add("wb-error"),n;t.logWarn("catched ",n),i.classList.add("wb-invalid"),s.setCustomValidity&&!s.validationMessage&&s.setCustomValidity(n.message),s.validationMessage&&s.reportValidity()})).finally((()=>{i.classList.remove("wb-busy")}))}_onChange(e){const t=pe.getEventInfo(e),i=t.node,s=t.colElem;i&&0!==t.colIdx?this._applyChange("change",i,s,e.target,{info:t,event:e,inputElem:e.target,inputValue:pe.util.getValueFromElem(e.target),inputValid:e.target.checkValidity()}):this.tree.log("Ignored change event for removed element or node title")}init(){super.init(),L(this.tree.element,"change",".contenteditable,input,textarea,select",(e=>this._onChange(e)))}_preprocessKeyEvent(e){const t=e.event,i=C(t),s=this.tree,n=this.getPluginOption("trigger");if(this.isEditingTitle()){switch(i){case"Enter":return this._stopEditTitle(!0,{event:t}),!1;case"Escape":return this._stopEditTitle(!1,{event:t}),!1}return!1}if(s.isRowNav()||0===s.activeColIdx){switch(i){case"Enter":if(n.indexOf("macEnter")>=0&&d)return this.startEditTitle(),!1;break;case"F2":if(n.indexOf("F2")>=0)return this.startEditTitle(),!1}return!0}return!0}isEditingTitle(e){return e?this.curEditNode===e:!!this.curEditNode}startEditTitle(e){e=null!=e?e:this.tree.getActiveNode();const t=this.getPluginOption("validity"),i=this.getPluginOption("select");if(!e)return;this.tree.logDebug(`startEditTitle(node=${e})`);let s=e._callEvent("edit.beforeEdit");if(!1===s)return void e.logDebug("beforeEdit canceled operation.");if(!0===s||!s){const t=m(e.title);let i=this.getPluginOption("maxlength");const n=i?` maxlength="${i}"`:"";i=this.getPluginOption("minlength");s=`0?" required":""}${i?` minlength="${i}"`:""}${n} >`}const n=e.getColElem(0).querySelector(".wb-title");n.innerHTML=s;const r=n.firstElementChild;t&&r.addEventListener("keydown",(t=>{r.setCustomValidity(""),r.reportValidity()||e.logWarn(`Invalid input: '${r.value}'`)})),r.focus(),i&&r.select(),this.curEditNode=e,e._callEvent("edit.edit",{inputElem:r})}stopEditTitle(e){return this._stopEditTitle(e,{})}_stopEditTitle(e,t){null!=t||(t={});const i=document.activeElement;let s=i?w(i):null;const n=this.curEditNode,r=!!t.forceClose,o=this.getPluginOption("validity");if(s&&this.getPluginOption("trim")&&(s=s.trim()),n)if(n.logDebug(`stopEditTitle(${e})`,t,i,s),e&&null!==s&&s!==n.title){const e=i.validationMessage;if(e)throw new Error(`Input validation failed for "${s}": ${e}.`);const t=n.getColElem(0);this._applyChange("edit.apply",n,t,i,{oldValue:n.title,newValue:s,inputElem:i,inputValid:i.checkValidity()}).then((e=>{const t=i.validationMessage;if(o&&t&&!1!==e)throw new Error(`Edit apply validation failed for "${s}": ${t}.`);(r||!1!==e)&&(null==n||n.setTitle(s),this.curEditNode._render({preventScroll:!0}),this.curEditNode=null,this.relatedNode=null,this.tree.setFocus())}))}else this.curEditNode._render({preventScroll:!0}),this.curEditNode=null,this.relatedNode=null,this.tree.setFocus();else this.tree.logDebug("stopEditTitle: not in edit mode.")}createNode(e="after",t,i){const s=this.tree;if(f(t=null!=t?t:s.getActiveNode(),"No node was passed, or no node is currently active."),e=e||"prependChild",null==i?i={title:""}:"string"==typeof i?i={title:i}:f(T(i),`Expected a plain object: ${i}`),("prependChild"===e||"appendChild"===e)&&(null==t?void 0:t.isExpandable(!0)))return void t.setExpanded().then((()=>{this.createNode(e,t,i)}));const n=t.addNode(i,e);n.setClass("wb-edit-new"),this.relatedNode=t,n.match=!0,n.makeVisible({noAnimation:!0}).then((()=>{this.startEditTitle(n)}))}} +/*! + * wunderbaum.ts + * + * A treegrid control. + * + * Copyright (c) 2021-2023, Martin Wendt (https://wwWendt.de). + * https://github.com/mar10/wunderbaum + * + * Released under the MIT license. + * @version v0.8.2 + * @date Sat, 17 Feb 2024 07:32:06 GMT + */class ue extends ce{constructor(e){super(e,null,{key:"__root__",title:e.id})}toString(){return`WbSystemRoot@${this.key}<'${this.tree.id}'>`}}class pe{get activeNode(){var e;return(null===(e=this._activeNode)||void 0===e?void 0:e.tree)?this._activeNode:null}get focusNode(){var e;return(null===(e=this._focusNode)||void 0===e?void 0:e.tree)?this._focusNode:null}constructor(e){this.enabled=!0,this.data={},this.extensionList=[],this.extensions={},this.keyMap=new Map,this.refKeyMap=new Map,this.treeRowCount=0,this._disableUpdateCount=0,this._disableUpdateIgnoreCount=0,this._activeNode=null,this._focusNode=null,this.types={},this.columns=[],this._columnsById={},this.pendingChangeTypes=new Set,this._util=U,this.filterMode=null,this.activeColIdx=0,this._cellNavMode=!1,this.lastQuicksearchTime=0,this.lastQuicksearchTerm="",this.lastClickTime=0;const t=this.options=N({id:null,source:null,element:null,debugLevel:3,header:null,rowHeightPx:Q,iconMap:"bootstrap",columns:null,types:null,enabled:!0,fixedCol:!1,showSpinner:!1,checkbox:!1,minExpandLevel:0,emptyChildListExpandable:!1,skeleton:!1,connectTopBreadcrumb:null,selectMode:"multi",navigationModeOption:null,quicksearch:!0,iconBadge:null,change:null,error:null,receive:null,strings:{loadError:"Error",loading:"Loading...",noData:"No data"}},e),i=new le;this.ready=i.promise();let s=!1;if(this.ready.then((()=>{s=!0;try{this._callEvent("init")}catch(e){this.logError("Exception inside `init(e)` event:",e)}})).catch((e=>{if(s)throw e;this._callEvent("init",{error:e})})),this.id=t.id||"wb_"+ ++pe.sequence,this.root=new ue(this),this._registerExtension(new B(this)),this._registerExtension(new he(this)),this._registerExtension(new W(this)),this._registerExtension(new ne(this)),this._registerExtension(new oe(this)),this._registerExtension(new G(this)),this._updateViewportThrottled=O(this._updateViewportImmediately.bind(this),{}),this.columns=t.columns,delete t.columns,!this.columns||!this.columns.length){const e="string"==typeof t.header?t.header:this.id;this.columns=[{id:"*",title:e,width:"*"}]}t.types&&this.setTypes(t.types,!0),delete t.types,this.element=k(t.element),f(!!this.element,`Invalid 'element' option: ${t.element}`),this.element.classList.add("wunderbaum"),this.element.getAttribute("tabindex")||(this.element.tabIndex=0),this.element._wb_tree=this,this.headerElement=this.element.querySelector("div.wb-header");const n=null==t.header?this.columns.length>1:!!t.header;if(this.headerElement){f(!this.columns,"`opts.columns` must not be set if markup already contains a header"),this.columns=[];const e=this.headerElement.querySelector("div.wb-row");for(const t of e.querySelectorAll("div"))this.columns.push({id:t.dataset.id||`col_${this.columns.length}`,title:""+t.textContent,width:"*"})}else{const e="".repeat(this.columns.length);if(this.element.innerHTML=`\n
    \n
    \n ${e}\n
    \n
    `,!n){this.element.querySelector("div.wb-header").style.display="none"}}this.element.innerHTML+='\n
    \n
    \n
    ',this.listContainerElement=this.element.querySelector("div.wb-list-container"),this.nodeListElement=this.listContainerElement.querySelector("div.wb-node-list"),this.headerElement=this.element.querySelector("div.wb-header"),this.element.classList.toggle("wb-grid",this.columns.length>1),this._initExtensions(),["enabled","fixedCol"].forEach((e=>{null!=t[e]&&this.setOption(e,t[e])})),t.source?(t.showSpinner&&(this.nodeListElement.innerHTML="loading..."),this.load(t.source).then((()=>{null==t.navigationModeOption?this.isGrid()?this.setNavigationOption(z.cell):this.setNavigationOption(z.row):this.setNavigationOption(t.navigationModeOption),this.update($.structure,{immediate:!0}),i.resolve()})).catch((e=>{i.reject(e)})).finally((()=>{var e;null===(e=this.element.querySelector("progress.spinner"))||void 0===e||e.remove(),this.element.classList.remove("wb-initializing")}))):i.resolve(),this.update($.any),this.element.addEventListener("scroll",(e=>{this.update($.scroll)})),this.resizeObserver=new ResizeObserver((e=>{this.update($.resize)})),this.resizeObserver.observe(this.element),L(this.nodeListElement,"click","div.wb-row",(t=>{const i=pe.getEventInfo(t),s=i.node,n=t;if(!1===this._callEvent("click",{event:t,node:s,info:i}))return this.lastClickTime=Date.now(),!1;if(s){if(n.ctrlKey)return void s.toggleSelected();const r=this.getOption("edit.trigger"),o=this.getOption("edit.slowClickDelay");r.indexOf("clickActive")>=0&&"title"===i.region&&s.isActive()&&(!o||Date.now()-this.lastClickTime=0?s.setActive(!0,{colIdx:i.colIdx,event:t}):s.setActive(!0,{event:t}),i.region===F.expander?s.setExpanded(!s.isExpanded(),{scrollIntoView:!1!==e.scrollIntoViewOnExpandClick}):i.region===F.checkbox&&s.toggleSelected()}this.lastClickTime=Date.now()})),L(this.nodeListElement,"dblclick","div.wb-row",(e=>{const t=pe.getEventInfo(e),i=t.node;if(!1===this._callEvent("dblclick",{event:e,node:i,info:t}))return!1;i&&0===t.colIdx&&i.isExpandable()&&(this._callMethod("edit._stopEditTitle"),i.setExpanded(!i.isExpanded()))})),L(this.element,"keydown",(e=>{const t=pe.getEventInfo(e),i=C(e),s=t.node||this.getFocusNode();this._callHook("onKeyEvent",{event:e,node:s,info:t,eventName:i})})),L(this.element,"focusin focusout",(e=>{const i="focusin"===e.type,s=pe.getNode(e);this._callEvent("focus",{flag:i,event:e}),i&&this.isRowNav()&&!this.isEditingTitle()&&(t.navigationModeOption===z.row?null==s||s.setActive():this.setCellNav()),i||this._callMethod("edit._stopEditTitle",!0,{event:e,forceClose:!0})}))}static getTree(e){if(e instanceof pe)return e;if(e instanceof ce)return e.tree;if(void 0===e&&(e=0),"number"==typeof e)e=document.querySelectorAll(".wunderbaum")[e];else if("string"==typeof e){for(const t of document.querySelectorAll(".wunderbaum")){const i=t._wb_tree;if(i&&i.id===e)return i}if(!(e=document.querySelector(e)))return null}else e.target&&(e=e.target);return f(e instanceof Element,`Invalid el type: ${e}`),e.matches(".wunderbaum")||(e=e.closest(".wunderbaum")),e&&e._wb_tree?e._wb_tree:null}get iconMap(){const e=this.options.iconMap;return"string"==typeof e?J[e]:e}static getNode(e){if(!e)return null;if(e instanceof ce)return e;for(void 0!==e.target&&(e=e.target);e;){if(e._wb_node)return e._wb_node;e=e.parentElement}return null}*[Symbol.iterator](){yield*this.root}_registerExtension(e){this.extensionList.push(e),this.extensions[e.id]=e}_initExtensions(){for(const e of this.extensionList)e.init()}_registerNode(e){const t=e.key;f(null!=t,`Missing key: '${e}'.`),f(!this.keyMap.has(t),`Duplicate key: '${t}': ${e}.`),this.keyMap.set(t,e);const i=e.refKey;if(null!=i){const t=this.refKeyMap.get(i);t?t.add(e):this.refKeyMap.set(i,new Set([e]))}}_unregisterNode(e){const t=e.refKey;if(null!=t){const i=this.refKeyMap.get(t);i&&i.delete(e)&&!i.size&&this.refKeyMap.delete(t)}this.keyMap.delete(e.key),e.tree=null,e.parent=null,e.removeMarkup()}_callHook(e,t={}){let i;const s=N({},{tree:this,options:this.options,result:void 0},t);for(const t of this.extensionList){if(i=t[e].call(t,s),!1===i)break;void 0!==s.result&&(i=s.result)}return i}_callMethod(e,...t){const[i,s]=e.split("."),n=s?this.extensions[i]:this,r=n[s];if(r)return r.apply(n,t);this.logError(`Calling undefined method '${e}()'.`)}_callEvent(e,t){const[i,s]=e.split("."),n=this.options,r=s?n[i][s]:n[i];if(r)return r.call(this,N({type:e,tree:this,util:this._util},t))}_getNodeByRowIdx(e){let t=null;return this.visitRows((i=>{if(i._rowIdx===e)return t=i,!1})),t}getTopmostVpNode(e=!0){const t=this.element.scrollTop;let i;return i=e?Math.ceil((t-1)/Q):Math.floor(t/Q),this._getNodeByRowIdx(i)}getLowestVpNode(e=!0){const t=this.element,i=this.headerElement.clientHeight,s=t.scrollTop,n=t.clientHeight-i;let r;return r=e?Math.floor((s+n)/Q)-1:Math.ceil((s+n)/Q)-1,r=Math.min(r,this.count(!0)-1),this._getNodeByRowIdx(r)}_getPrevNodeInView(e,t=1){return this.visitRows((i=>{if(e=i,t--<=0)return!1}),{reverse:!0,start:e||this.getActiveNode()}),e}_getNextNodeInView(e,t=1){return this.visitRows((i=>{if(e=i,t--<=0)return!1}),{reverse:!1,start:e||this.getActiveNode()}),e}addChildren(e,t){return this.root.addChildren(e,t)}applyCommand(e,t,i){let s,n;switch(t instanceof ce?s=t:(s=this.getActiveNode(),f(void 0===i,`Unexpected options: ${i}`),i=t),e){case"moveUp":n=s.getPrevSibling(),n&&(s.moveTo(n,"before"),s.setActive());break;case"moveDown":n=s.getNextSibling(),n&&(s.moveTo(n,"after"),s.setActive());break;case"indent":n=s.getPrevSibling(),n&&(s.moveTo(n,"appendChild"),n.setExpanded(),s.setActive());break;case"outdent":s.isTopLevel()||(s.moveTo(s.getParent(),"after"),s.setActive());break;case"remove":n=s.getPrevSibling()||s.getParent(),s.remove(),n&&n.setActive();break;case"addChild":this._callMethod("edit.createNode","prependChild");break;case"addSibling":this._callMethod("edit.createNode","after");break;case"rename":s.startEditTitle();break;case"down":case"first":case"last":case"left":case"pageDown":case"pageUp":case"parent":case"right":case"up":return s.navigate(e);default:v(`Unhandled command: '${e}'`)}}clear(){this.root.removeChildren(),this.root.children=null,this.keyMap.clear(),this.refKeyMap.clear(),this.treeRowCount=0,this._activeNode=null,this._focusNode=null,this.update($.structure)}destroy(){this.logInfo("destroy()..."),this.clear(),this.resizeObserver.disconnect(),this.element.innerHTML="",this.element.outerHTML=this.element.outerHTML}getOption(e,t){let i,s=this.options;e.indexOf(".")>=0&&([i,e]=e.split("."),s=s[i]);let n=s[e];return"function"==typeof n&&(n=n({type:"resolve",tree:this})),null!=n?n:t}setOption(e,t){if(e.indexOf(".")>=0){const i=e.split(".");this.extensions[i[0]].setPluginOption(i[1],t)}else switch(this.options[e]=t,e){case"checkbox":this.update($.any);break;case"enabled":this.setEnabled(!!t);break;case"fixedCol":this.element.classList.toggle("wb-fixed-col",!!t)}}hasFocus(){return this.element.contains(document.activeElement)}hasHeader(){const e=this.options.header;return this.isGrid()?!1!==e:!!e}runWithDeferredUpdate(e,t=null){try{this.enableUpdate(!1);const t=e();return f(!(t instanceof Promise),`Promise return not allowed: ${t}`),t}finally{this.enableUpdate(!0)}}async expandAll(e=!0,t){await this.root.expandAll(e,t)}selectAll(e=!0){return this.root.setSelected(e,{propagateDown:!0})}toggleSelect(){this.selectAll(this.root._anySelectable())}getSelectedNodes(e=!1){return this.root.getSelectedNodes(e)}_selectRange(e){this.logDebug("_selectRange",e),v("Not yet implemented.")}count(e=!1){return e?this.treeRowCount:this.keyMap.size}_check(){let e=0;this.visit((t=>{e++})),this.keyMap.size!==e&&this.logWarn(`_check failed: ${this.keyMap.size} !== ${e}`)}findAll(e){return this.root.findAll(e)}findByRefKey(e){const t=this.refKeyMap.get(e);return t?Array.from(t):[]}findFirst(e){return this.root.findFirst(e)}findKey(e){return this.keyMap.get(e)||null}findNextNode(e,t){let i=null;const s=this.getFirstChild(),n="string"==typeof e?function(e){e=y(e);const t=new RegExp("^"+e,"i");return function(e){return t.test(e.title)}}(e):e;function r(e){if(n(e)&&(i=e),i||e===t)return!1}return t=t||s,this.visitRows(r,{start:t,includeSelf:!1}),i||t===s||this.visitRows(r,{start:s,includeSelf:!0}),i}findRelatedNode(e,t,i=!1){let s=null;const n=Math.floor(this.listContainerElement.clientHeight/Q);switch(t){case"parent":case"left":e.parent&&e.parent.parent&&(s=e.parent);break;case"first":this.visit((e=>{if(e.isVisible())return s=e,!1}));break;case"last":this.visit((e=>{e.isVisible()&&(s=e)}));break;case"right":e.children&&e.children.length&&(s=e.children[0]);break;case"up":s=this._getPrevNodeInView(e);break;case"down":s=this._getNextNodeInView(e);break;case"pageDown":{const t=this.getLowestVpNode();s=e._rowIdxt._rowIdx?t:this._getPrevNodeInView(e,n)}break;default:this.logWarn("Unknown relation '"+t+"'.")}return s}*format_iter(e,t){yield*this.root.format_iter(e,t)}format(e,t){return this.root.format(e,t)}getActiveColElem(){return this.activeNode&&this.activeColIdx>=0?this.activeNode.getColElem(this.activeColIdx):null}getActiveNode(){return this.activeNode}getFirstChild(){return this.root.getFirstChild()}getFocusNode(){return this.focusNode}static getEventInfo(e){const t=e.target,i=t.classList,s=t.closest("span.wb-col"),n=pe.getNode(t),r=n?n.tree:pe.getTree(e),o={event:e,canonicalName:C(e),tree:r,node:n,region:F.unknown,colDef:void 0,colIdx:-1,colId:void 0,colElem:s};if(i.contains("wb-title"))o.region=F.title;else if(i.contains("wb-expander"))o.region=n.isExpandable()?F.expander:F.prefix;else if(i.contains("wb-checkbox"))o.region=F.checkbox;else if(i.contains("wb-icon"))o.region=F.icon;else if(i.contains("wb-node"))o.region=F.title;else if(s){o.region=F.column;const e=Array.prototype.indexOf.call(s.parentNode.children,s);o.colIdx=e}else{if(!i.contains("wb-row"))return"mousemove"===e.type||e instanceof KeyboardEvent||null==r||r.logWarn("getEventInfo(): not found",e,o),o;o.region=F.title}return-1===o.colIdx&&(o.colIdx=0),o.colDef=null==r?void 0:r.columns[o.colIdx],null!=o.colDef&&(o.colId=o.colDef.id),o}toString(){return`Wunderbaum<'${this.id}'>`}isEditing(){return!!this.nodeListElement.querySelector("input:focus,select:focus")}isEditingTitle(){return this._callMethod("edit.isEditingTitle")}isLoading(){let e=!1;return this.root.visit((t=>{if(t._isLoading||t._requestId)return e=!0,!1}),!0),e}log(...e){this.options.debugLevel>=4&&console.log(this.toString(),...e)}logDebug(...e){this.options.debugLevel>=4&&console.debug(this.toString(),...e)}logError(...e){this.options.debugLevel>=1&&console.error(this.toString(),...e)}logInfo(...e){this.options.debugLevel>=3&&console.info(this.toString(),...e)}logTime(e){return this.options.debugLevel>=4&&console.time(this+": "+e),e}logTimeEnd(e){this.options.debugLevel>=4&&console.timeEnd(this+": "+e)}logWarn(...e){this.options.debugLevel>=2&&console.warn(this.toString(),...e)}scrollTo(e){let t,i;e instanceof ce?t=e:(i=e,t=i.node),f(t&&null!=t._rowIdx,`Invalid node: ${t}`);const s=this.element,n=this.headerElement.clientHeight,r=s.scrollTop,o=s.clientHeight,l=t._rowIdx*Q+n,a=n,d=l-r,c=d+Q,h=null==i?void 0:i.topNode;let u=null;d>=a?c<=o||(u=l+Q-o+2):u=l-a-2,null!=u&&(this.log(`scrollTo(${l}): ${r} => ${u}`),s.scrollTop=u,h&&this.scrollTo(h))}scrollToHorz(){const e=this.columns[0]._widthPx,t=this.element.clientWidth,i=this.element.scrollLeft,s=this.getActiveColElem(),n=Number.parseInt(null==s?void 0:s.style.left,10),r=n+Number.parseInt(null==s?void 0:s.style.width,10);let o=i;n-it&&(o=r-t),o=Math.max(0,o),this.log(`scrollToHorz(${this.activeColIdx}): ${n}..${r}, fixedOfs=${e}, vpWidth=${t}, curLeft=${i} -> ${o}`),this.element.scrollLeft=o}setColumn(e,t){var i,s,n;const r=null==t?void 0:t.edit,o=!1!==(null==t?void 0:t.scrollIntoView);if(f(this.isCellNav(),"Expected cellNav mode"),"string"==typeof e){const t=e;f((e=this.columns.findIndex((t=>t.id===e)))>=0,`Invalid colId: ${t}`)}if(f(0<=e&&e0&&(s?this._updateViewportImmediately():this._updateViewportThrottled())}}setEnabled(e=!0){const t=this.enabled;return this.enabled=!!e,this.element.classList.toggle("wb-disabled",!e),t}isEnabled(){return this.enabled}isGrid(){return this.columns&&this.columns.length>1}isCellNav(){return!!this._cellNavMode}isRowNav(){return!this._cellNavMode}setCellNav(e=!0){var t;const i=this._cellNavMode;this._cellNavMode=!!e,e&&!i&&this.setColumn(0),this.element.classList.toggle("wb-cell-mode",e),null===(t=this.activeNode)||void 0===t||t.update($.status)}setNavigationOption(e,t=!1){if(this.isGrid()||e===z.row)switch(this.options.navigationModeOption=e,e){case z.cell:this.setCellNav(!0);break;case z.row:this.setCellNav(!1);break;case z.startCell:t&&this.setCellNav(!0);break;case z.startRow:t&&this.setCellNav(!1);break;default:v(`Invalid mode '${e}'.`)}else this.logWarn("Plain trees only support row navigation mode.")}setStatus(e,t){return this.root.setStatus(e,t)}setTypes(e,t=!0){f(T(e),`Expected plain objext: ${e}`),t?this.types=e:N(this.types,e);for(const e of Object.values(this.types))e.classes&&(e.classes=A(e.classes))}sortChildren(e=te,t=!1){this.root.sortChildren(e,t)}toDictArray(e){var t;return null!==(t=this.root.toDict(!0,e).children)&&void 0!==t?t:[]}_updateColumnWidths(){const e=this.element.clientWidth,t=this.columns,i=t[0];let s=0,n=0,r=0,o=!1;if("*"!==i.id)throw new Error(`First column must have id '*': got '${i.id}'.`);this._columnsById={};for(const e of t){this._columnsById[e.id]=e;const t=e.width;if("*"===e.id&&e!==i)throw new Error(`Column id '*' must be defined only once: '${e.title}'.`);if(t&&"*"!==t)if("number"==typeof t)e._weight=t,n+=t;else if("string"==typeof t&&t.endsWith("px")){e._weight=0;const i=parseFloat(t.slice(0,-2));e._widthPx!=i&&(o=!0,e._widthPx=i),r+=i}else v(`Invalid column width: ${t} (expected string ending with 'px' or number, e.g. "px" or ).`);else e._weight=1,n+=1}const l=Math.max(0,e-r);let a=0;for(const e of t){let t;if(e._weight){const i=e.minWidth;t="number"==typeof i?i:"string"==typeof i&&i.endsWith("px")?parseFloat(i.slice(0,-2)):4;const s=Math.max(t,l*e._weight/n);e._widthPx!=s&&(o=!0,e._widthPx=s)}e._ofsPx=a,a+=e._widthPx}t[t.length-1]._widthPx-=1,s=a-1;const d=`${s}px`;return this.headerElement.style.width=d,this.listContainerElement.style.width=d,o}_renderHeaderMarkup(){f(this.headerElement,"Expected a headerElement");const e=this.hasHeader();if(E(this.headerElement,e),!e)return;const t=this.columns.length,i=this.headerElement.querySelector(".wb-row");f(i,"Expected a row in header element"),i.innerHTML="".repeat(t);for(let e=0;e${r}${l}`,this.isCellNav()&&n.classList.toggle("wb-active",e===this.activeColIdx)}}updatePendingModifications(){this.pendingChangeTypes.size>0&&this._updateViewportImmediately()}_updateViewportImmediately(){var e;if(this._disableUpdateCount)return this.log(`_updateViewportImmediately() IGNORED (disable level: ${this._disableUpdateCount}).`),void this._disableUpdateIgnoreCount++;this._updateViewportThrottled.pending()&&this._updateViewportThrottled.cancel();const t=P,i=new Set(this.pendingChangeTypes);this.pendingChangeTypes.clear();if(i.has(t.scroll)&&1===i.size)this._updateRows({newNodesOnly:!0});else{if(this.log("_updateViewportImmediately():",i),!1!==this.options.adjustHeight){let e=this.listContainerElement.clientHeight;const t=this.headerElement.clientHeight,i=this.element.clientHeight-t-1;Math.abs(e-i)>1&&(this.listContainerElement.style.height=i+"px",e=i)}i.has(t.clearMarkup)&&this.visit((e=>{e.removeMarkup()})),i.has(t.header)&&(this._updateColumnWidths(),this._renderHeaderMarkup()),this._updateRows()}if(this.options.connectTopBreadcrumb){let t=null===(e=this.getTopmostVpNode(!0))||void 0===e?void 0:e.getPath(!1,"title"," > ");t=t?t+" >":"",this.options.connectTopBreadcrumb.textContent=t}this._callEvent("update")}_updateRows(e){const t=!!(e=Object.assign({newNodesOnly:!1},e)).newNodesOnly,i=this.element.clientHeight,s=this.element.scrollTop;let n=Math.max(0,s/22-5);n=Math.floor(n),n%2&&n--;let r=Math.max(0,(s+i)/22+5);r=Math.ceil(r);const o=new Set;this.nodeListElement.childNodes.forEach((e=>{const t=e;o.add(t._wb_node)}));let l=0,a=0,d=!1,c="first";this.visitRows((function(e){const i=e._rowElem;e._rowIdx!==l&&(e._rowIdx=l,d=!0),lr?i&&(c=i):i&&t?(o.delete(e),i.style.top=l*Q+"px",c=i):(o.delete(e),i&&(i.style.top=l*Q+"px"),e._render({top:a,after:c}),c=e._rowElem),l++,a+=22})),this.treeRowCount=l;for(const e of o)e._callEvent("discard"),e.removeMarkup();return this.nodeListElement.style.height=`${a}px`,d}visit(e){return this.root.visit(e,!1)}visitRows(e,t){if(!this.root.hasChildren())return!1;if(t&&t.reverse)return delete t.reverse,this._visitRowsUp(e,t);let i,s,n,r,o,l,a=0,d=!1===(t=t||{}).includeSelf,c=t.start||this.root.children[0];const h=!!t.includeHidden,u=!h&&"hide"===this.filterMode;for(n=c.parent;n;){for(o=n.children,s=o.indexOf(c)+a,f(s>=0,`Could not find ${c} in parent's children: ${n}`),i=s;it!==l&&(!u||t.match||t.subMatchCount?!1!==e(t)&&(h||!t.children||t.expanded?void 0:"skip"):"skip")),!1),!1===r))return!1}}c=n,n=n.parent,a=1,!n&&t.wrap&&(this.logDebug("visitRows(): wrap around"),f(t.start,"`wrap` option requires `start`"),l=t.start,t.wrap=!1,n=this.root,a=0)}return!0}_visitRowsUp(e,t){let i,s,n,r=t.start||this.root.children[0];const o=!!t.includeHidden;if(!1!==t.includeSelf&&!1===e(r))return!1;for(;;){if(n=r.parent,i=n.children,i[0]===r){if(r=n,!r.parent)break;i=n.children}else for(s=i.indexOf(r),r=i[s-1];(o||r.expanded)&&r.children&&r.children.length;)i=r.children,n=r,r=i[i.length-1];if((o||r.isVisible())&&!1===e(r))return!1}return!0}load(e){return this.clear(),this.root.load(e)}enableUpdate(e){e?(f(this._disableUpdateCount>0,"enableUpdate(true) was called too often"),this._disableUpdateCount--,0===this._disableUpdateCount&&(this.logDebug(`enableUpdate(): active again. Re-painting to catch up with ${this._disableUpdateIgnoreCount} ignored update requests...`),this._disableUpdateIgnoreCount=0,this.update($.any,{immediate:!0}))):this._disableUpdateCount++}filterNodes(e,t){return this.extensions.filter.filterNodes(e,t)}filterBranches(e,t){return this.extensions.filter.filterBranches(e,t)}clearFilter(){return this.extensions.filter.clearFilter()}isFilterActive(){return!!this.filterMode}updateFilter(){return this.extensions.filter.updateFilter()}}pe.sequence=0,pe.version="v0.8.2",pe.util=U,e.Wunderbaum=pe})); +//# sourceMappingURL=wunderbaum.umd.min.js.map diff --git a/orochi/static/js/wunderbaum/wunderbaum.umd.min.js.map b/orochi/static/js/wunderbaum/wunderbaum.umd.min.js.map new file mode 100644 index 00000000..d7535173 --- /dev/null +++ b/orochi/static/js/wunderbaum/wunderbaum.umd.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"wunderbaum.umd.js","names":["global","factory","exports","module","define","amd","globalThis","self","mar10","this","freeGlobal","Object","freeGlobalThis","freeSelf","root","Function","isObject","value","type","debounce","func","wait","options","lastArgs","lastThis","maxWait","result","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","useRAF","requestAnimationFrame","TypeError","invokeFunc","time","args","thisArg","undefined","apply","startTimer","pendingFunc","cancelAnimationFrame","setTimeout","shouldInvoke","timeSinceLastCall","timerExpired","Date","now","trailingEdge","timeSinceLastInvoke","timeWaiting","Math","min","remainingWait","debounced","isInvoking","leadingEdge","max","cancel","id","clearTimeout","cancelTimer","flush","pending","throttle","MOUSE_BUTTONS","isMac","nav","navigator","test","platform","_getUserInfo","REX_HTML","REX_TOOLTIP","ENTITY_MAP","ValidationError","Error","constructor","message","super","name","assert","cond","msg","documentReady","callback","document","readyState","addEventListener","error","escapeHtml","s","replace","escapeRegex","escapeTooltip","getValueFromElem","elem","coerce","tag","tagName","classList","contains","span","embeddedInput","querySelector","innerText","input","indeterminate","checked","valueAsDate","valueAsNumber","parentElement","setElemDisplay","flag","style","elemFromSelector","display","elemFromHtml","html","t","createElement","innerHTML","trim","content","firstElementChild","_IGNORE_KEYS","Set","obj","eventToString","event","key","et","altKey","push","ctrlKey","metaKey","shiftKey","button","has","join","extend","i","length","arg","prototype","hasOwnProperty","call","isArray","Array","isEmptyObject","keys","isPlainObject","toString","onEvent","rootTarget","eventNames","selectorOrHandler","handlerOrNone","selector","handler","split","forEach","evn","e","target","matches","closest","overrideMethod","instance","methodName","ctx","prevSuper","prevSuperApply","prevFunc","_super","_superApply","argsArray","getOption","opts","defaultValue","ext","indexOf","toSet","val","set","c","add","adaptiveThrottle","assign","minDelay","defaultDelay","maxDelay","delayFactor","waiting","pendingArgs","pendingTimer","throttledFn","useArgs","start","console","elap","curDelay","useDelay","ChangeType","RenderFlag","NodeStatusType","NodeRegion","NavModeEnum","util","freeze","__proto__","Deferred","thens","catches","status","resolve","resolvedValue","reject","rejectedError","then","cb","unshift","promise","catch","MAX_INT","documentReadyPromise","Promise","each","k","extractHtmlText","isFunction","noop","setTimeoutPromise","ms","err","setValueToElem","select","selectedIndex","sleep","async","toggleCheckbox","element","tristate","toLowerCase","WunderbaumExtension","tree","defaults","enabled","treeOpts","extensionOpts","getPluginOption","init","_a","setPluginOption","setEnabled","onKeyEvent","data","onRender","START_MARKER","END_MARKER","RE_START_MARKER","RegExp","RE_END_MARTKER","FilterExtension","connectInput","autoApply","autoExpand","counter","fuzzy","hideExpandedCounter","hideExpanders","highlight","leavesOnly","mode","noData","lastFilterArgs","queryInput","filterNodes","filterMode","updateFilter","_applyFilterNoUpdate","filter","branchMode","_opts","runWithDeferredUpdate","_applyFilterImpl","match","temp","count","prevAutoCollapse","autoCollapse","hideMode","logInfo","clearFilter","map","reduce","a","b","re","reHighlight","node","title","text","res","escapeTitles","matchingIndices","_matchingArrIdx","_mIdx","textPoses","v","_markFuzzyMatchedChars","titleWithHighlight","arguments","toggle","subMatchCount","visit","setStatus","ok","children","matchedByBranch","parent","visitParents","p","expanded","setExpanded","noAnimation","noEvents","_filterAutoExpanded","filterBranches","logWarn","enableUpdate","remove","KeynavExtension","_getEmbeddedInputElem","ace","getActiveColElem","_isCurInputFocused","activate","autoActivate","curInput","inputHasFocus","navModeOption","navigationModeOption","focusNode","eventName","handled","isEnabled","_callEvent","_callMethod","currentNode","getFocusNode","getActiveNode","firstNode","getFirstChild","setActive","setFocus","isColspan","isRowNav","blur","_render","quicksearch","stamp","lastQuicksearchTime","lastQuicksearchTerm","matchNode","findNextNode","preventDefault","isActive","isExpanded","isExpandable","startCell","startRow","setCellNav","toggleSelected","navigate","curInputType","inputCanFocus","logDebug","setCustomValidity","setColumn","activeColIdx","checkValidity","focus","click","log","isCellNav","cell","columns","LoggerExtension","ignoreEvents","prefix","extra","ROW_HEIGHT","TEST_IMG","iconMaps","bootstrap","loading","expanderExpanded","expanderCollapsed","expanderLazy","checkChecked","checkUnchecked","checkUnknown","radioChecked","radioUnchecked","radioUnknown","folder","folderOpen","folderLazy","doc","fontawesome6","RESERVED_TREE_SOURCE_KEYS","KEY_TO_ACTION_DICT","Add","ArrowDown","ArrowLeft","ArrowRight","ArrowUp","Backspace","Divide","End","Home","Multiply","PageDown","PageUp","Subtract","makeNodeTitleMatcher","nodeTitleSorter","x","y","decompressSourceData","source","_format","_version","_keyMap","_valueMap","longToShort","shortToLong","entries","warn","_typeList","_b","_c","_positional","includes","positionalShort","newChildren","keyToNodeMap","indexToNodeMap","keyAttrName","childrenAttrName","index","nodeTuple","parentId","kwargs","positionalIdx","parentNode","unflattenSource","_iter","childList","getOwnPropertyNames","propName","longName","newValue","nodeMimeType","DndExtension","autoExpandMS","multiSource","effectAllowed","dropEffectDefault","guessDropEffect","preventForeignNodes","preventLazyParents","preventNonNodes","preventRecursion","preventSameParent","preventVoidMoves","serializeClipboardData","scroll","scrollSensitivity","scrollSpeed","sourceCopyHook","dragStart","drag","dragEnd","dragEnter","dragOver","dragExpand","drop","dragLeave","srcNode","lastTargetNode","lastEnterStamp","lastAllowedDropRegions","lastDropEffect","lastDropRegion","currentScrollDir","applyScrollDirThrottled","_applyScrollDir","dndOpts","dnd","onDragEvent","bind","onDropEvent","_leaveNode","ltn","setClass","unifyDragover","size","_calcDropRegion","allowed","dy","offsetY","_guessDropEffect","ea","canCopy","canLink","canMove","_isVoidDrop","targetNode","dropRegion","getNextSibling","getPrevSibling","isDragging","sp","scrollTop","_autoScroll","viewportY","sensitivity","headerHeight","headerElement","clientHeight","height","offsetHeight","scrollHeight","Wunderbaum","getNode","dataTransfer","isEditingTitle","nodeData","toDict","n","_orgKey","_treeId","setData","JSON","stringify","types","srcTree","dt","_t","pred","dropEffect","isStatusNode","isLoaded","isAncestorOf","regionSet","sourceNode","clientY","offsetTop","region","_isLoading","stopPropagation","getData","parse","suggestedDropMode","suggestedDropEffect","sourceNodeData","DragObserver","dragElem","dragging","events","thresh","_handler","handleEvent","disconnect","removeEventListener","getDragElem","stopDrag","cb_event","dragstop","dx","pageX","pageY","dragstart","GridExtension","observer","window","handleDrag","info","getEventInfo","_promise","_resolve","_reject","reason","finally","NODE_PROPS","NODE_DICT_PROPS","delete","WunderbaumNode","refKey","classes","_requestId","_errorInfo","_partsel","_partload","_rowIdx","_rowElem","sequence","icon","lazy","statusNodeType","colspan","checkbox","radiogroup","selected","unselectable","_registerNode","Symbol","iterator","cl","l","typeInfo","addChildren","before","applyMinExpanLevel","_level","getLevel","nodeList","forceExpand","minExpandLevel","child","subChildren","isUnloaded","concat","findDirectChild","pos","splice","update","structure","addNode","applyCommand","cmd","collapseSiblings","className","cnSet","cn","startEditTitle","expandAll","depth","loadLazy","force","keepActiveNodeVisible","expandOpts","scrollIntoView","logTime","level","level_1","promises","all","logTimeEnd","activeNode","findAll","matcher","ptr","findFirst","findRelatedNode","where","includeHidden","format_iter","name_cb","connectors","_is_last","ca","_format_line","parts","format","line","getColElem","colIdx","findIndex","colElems","querySelectorAll","getCloneList","includeSelf","clones","findByRefKey","getLastChild","ac","idx","getParent","getParentList","includeRoot","dtn","getPath","part","separator","path","isFunc","hasChildren","hasClass","other","isDescendantOf","isChildOf","isClone","andCollapsed","emptyChildListExpandable","isFirstSibling","isLastSibling","isLazy","isLoading","isPagingNode","isParentOf","isPartload","isPartsel","isRadio","isRendered","isRootNode","isSelected","isTopLevel","isVisible","hasFilter","parents","_loadSourceObject","response","setTypes","colStructure","selectMode","fixSelection3FromEndNodes","_fetchWithOptions","url","params","body","rest","fetchOpts","method","URLSearchParams","fetch","json","load","requestId","prevParent","elapLoad","elapProcess","startProcess","logError","debugLevel","forceReload","wasExpanded","resetLazy","debug","makeVisible","dfd","deferreds","len","seOpts","updatePendingModifications","moveTo","targetParent","triggerModifyChild","any","triggerModify","removeMarkup","_unregisterNode","removeChildren","_setFocusNode","_wb_node","_getRenderInfo","allColInfosById","renderColInfosById","col","_createIcon","iconMap","parentElem","replaceChild","showLoading","iconSpan","appendChild","cbRes","badge","tooltip","badgeClass","badgeTooltip","append","_render_markup","treeOptions","rowDiv","checkboxSpan","expanderSpan","isNew","after","top","nodeElem","ofsTitlePx","titleSpan","_ofsTitlePx","draggable","colElem","left","_ofsPx","width","_widthPx","nodeListElement","prepend","_render_data","preventScroll","textContent","skeleton","vpWidth","clientWidth","isDataChange","_render_status","renderInfo","rowClasses","image","backgroundImage","cbclass","colSpan","resizeCols","ofs","colDef","change","row","recursive","dict","scrollTo","prev","retrigger","focusTree","orgEvent","edit","nextNode","prevNode","_setActiveNode","immediate","sendEvents","updateOpts","lastChild","topNode","setIcon","setKey","getSelectedNodes","stopOnParents","_anySelectable","setSelected","found","_changeSelectStatusProps","state","changed","fixSelection3AfterClick","_walk","allSelected","someSelected","canSelect","propagateDown","sibling","details","statusNode","_setStatusNode","firstChild","_clearStatusNode","strings","loadError","setTitle","_sortChildren","cmp","deep","sort","sortChildren","operation","modifyChild","visitSiblings","isMatched","EditExtension","minlength","maxlength","trigger","slowClickDelay","validity","beforeEdit","curEditNode","relatedNode","debouncedOnChange","_onChange","_applyChange","inputElem","validationMessage","reportValidity","inputValue","inputValid","_preprocessKeyEvent","_stopEditTitle","inputHtml","opt","stopEditTitle","focusElem","activeElement","forceClose","errMsg","oldValue","createNode","newNode","WbSystemRoot","_activeNode","_focusNode","extensionList","extensions","keyMap","Map","refKeyMap","treeRowCount","_disableUpdateCount","_disableUpdateIgnoreCount","_columnsById","pendingChangeTypes","_util","_cellNavMode","lastClickTime","header","rowHeightPx","fixedCol","showSpinner","connectTopBreadcrumb","iconBadge","receive","readyDeferred","ready","readyOk","_registerExtension","_updateViewportThrottled","_updateViewportImmediately","getAttribute","tabIndex","_wb_tree","wantHeader","rowElement","colDiv","dataset","coldivs","repeat","listContainerElement","_initExtensions","optName","setOption","isGrid","setNavigationOption","resizeObserver","ResizeObserver","resize","observe","mouseEvent","expander","scrollIntoViewOnExpandClick","_callHook","getTree","el","treeElem","Element","extension","rk","rks","get","hook","d","_getNodeByRowIdx","visitRows","getTopmostVpNode","complete","topIdx","ceil","floor","getLowestVpNode","scrollParent","bottomIdx","_getPrevNodeInView","reverse","_getNextNodeInView","nodeOrOpts","refNode","clear","destroy","outerHTML","hasFocus","hasHeader","hint","selectAll","toggleSelect","_selectRange","eventInfo","visible","_check","from","findKey","startNode","reMatch","makeNodeTitleStartMatcher","_checkNode","pageSize","bottomNode","parentCol","canonicalName","unknown","colId","column","KeyboardEvent","isEditing","label","timeEnd","vpHeight","rowTop","vpTop","vpRowTop","vpRowBottom","newScrollTop","scrollToHorz","fixedWidth","scrollLeft","colLeft","Number","parseInt","colRight","newLeft","cid","setActiveNode","RF","clearMarkup","redraw","reset","values","toDictArray","_updateColumnWidths","col0","totalWidth","totalWeight","modified","cw","_weight","endsWith","px","parseFloat","slice","restPx","ofsPx","minWidth","cmw","tw","_renderHeaderMarkup","colCount","headerRow","headerClasses","resizer","_updateRows","newNodesOnly","adjustHeight","wantHeight","abs","vp_height","startIdx","endIdx","obsoleteNodes","childNodes","tr","prevElem","_visitRowsUp","nextIdx","siblings","stopNode","siblingOfs","skipFirstNode","checkFilter","wrap","isFilterActive","version"],"sources":["wunderbaum.umd.js"],"mappings":"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"} diff --git a/orochi/templates/base.html b/orochi/templates/base.html index 3762c03f..ccba01be 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -12,7 +12,7 @@ {% block css %} - + @@ -163,13 +163,13 @@ language="javascript"> - + - diff --git a/orochi/templates/website/partial_pstree.html b/orochi/templates/website/partial_pstree.html deleted file mode 100644 index 62fd20b0..00000000 --- a/orochi/templates/website/partial_pstree.html +++ /dev/null @@ -1,28 +0,0 @@ -{% load custom_tags %} -{% include "website/partial_note.html" %} - -{% if not empty %} -
    - -{% else %} -
    - -
    -{% endif %} diff --git a/orochi/templates/website/partial_tree.html b/orochi/templates/website/partial_tree.html new file mode 100644 index 00000000..ff5ba346 --- /dev/null +++ b/orochi/templates/website/partial_tree.html @@ -0,0 +1,117 @@ +{% load custom_tags %} +{% include "website/partial_note.html" %} + +{% if not empty %} +
    + + + +
    + +
    +

    Loading…

    +
    +
    +
    + + +{% else %} +
    + +
    +{% endif %} diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index c1c7e4ad..4f0f141b 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -28,6 +28,7 @@ from django.conf import settings from elasticsearch import Elasticsearch, helpers from elasticsearch_dsl import Search +from regipy.exceptions import RegistryParsingException from regipy.registry import RegistryHive from volatility3 import cli, framework from volatility3.cli.text_renderer import ( @@ -39,6 +40,7 @@ optional, quoted_optional, ) +from volatility3.cli.volshell.generic import NullFileHandler from volatility3.framework import ( automagic, constants, @@ -79,33 +81,7 @@ } -class MuteProgress(object): - """ - Mutes progress for volatility plugin - """ - - def __init__(self): - self._max_message_len = 0 - - def __call__(self, progress: Union[int, float], description: Optional[str] = None): - pass - - def file_handler_class_factory(output_dir, file_list): - class NullFileHandler(io.BytesIO, interfaces.plugins.FileHandlerInterface): - """Null FileHandler that swallows files whole without consuming memory""" - - def __init__(self, preferred_name: str): - interfaces.plugins.FileHandlerInterface.__init__(self, preferred_name) - super().__init__() - - def writelines(self, lines): - """Dummy method""" - pass - - def write(self, data): - """Dummy method""" - return len(data) class OrochiFileHandler(interfaces.plugins.FileHandlerInterface): def __init__(self, filename: str): @@ -174,7 +150,7 @@ class ReturnJsonRenderer(JsonRenderer): if isinstance(x, interfaces.renderers.BaseAbsentValue) else x.isoformat() ), - "default": quoted_optional(lambda x: f"{x}"), + "default": lambda x: x, } def render(self, grid: interfaces.renderers.TreeGrid): @@ -186,7 +162,7 @@ def visitor( ) -> Tuple[Dict[str, Dict[str, Any]], List[Dict[str, Any]]]: # Nodes always have a path value, giving them a path_depth of at least 1, we use max just in case acc_map, final_tree = accumulator - node_dict = {"__children": []} + node_dict: Dict[str, Any] = {"__children": []} for column_index in range(len(grid.columns)): column = grid.columns[column_index] renderer = self._type_renderers.get( @@ -285,7 +261,7 @@ async def run_vt(filepath): "last_analysis_stats": stats, "scan_date": scan_date, "positives": stats.get("malicious", 0) + stats.get("suspicious", 0), - "total": sum(stats.get(x, 0) for x in stats.keys()) if stats else 0, + "total": sum(stats.get(x, 0) for x in stats) if stats else 0, "permalink": f"https://www.virustotal.com/api/v3/files/{to_check}", } with open(f"{filepath}.vt.json", "w") as f: @@ -302,8 +278,17 @@ def run_regipy(filepath): """ try: registry_hive = RegistryHive(filepath) - reg_json = registry_hive.recurse_subkeys(registry_hive.root, as_json=True) - root = {"values": [attr.asdict(entry) for entry in reg_json]} + data = [] + try: + data.extend( + attr.asdict(entry) + for entry in registry_hive.recurse_subkeys( + registry_hive.root, as_json=True + ) + ) + except RegistryParsingException as e: + logging.error(e) + root = {"values": data} root = json.loads(json.dumps(root).replace(r"\u0000", "")) with open(f"{filepath}.regipy.json", "w") as f: json.dump(root, f) @@ -418,7 +403,7 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None): automagics, plugin, base_config_path, - MuteProgress(), + cli.MuteProgress(), file_handler, ) except exceptions.UnsatisfiedException as excp: diff --git a/orochi/website/urls.py b/orochi/website/urls.py index 820714f7..3ae6433a 100644 --- a/orochi/website/urls.py +++ b/orochi/website/urls.py @@ -56,6 +56,7 @@ def to_url(self, value): path("plugins", views.plugins, name="plugins"), path("analysis", views.analysis, name="analysis"), path("generate", views.generate, name="generate"), + path("tree", views.tree, name="tree"), path("plugin", views.plugin, name="plugin"), path("parameters", views.parameters, name="parameters"), path("export", views.export, name="export"), diff --git a/orochi/website/views.py b/orochi/website/views.py index 92d11854..1c616f5c 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -89,7 +89,6 @@ """ - SYSTEM_COLUMNS = [ "orochi_createdAt", "orochi_os", @@ -97,16 +96,16 @@ "down_path", ] -PLUGIN_WITH_CHILDREN = [ - "frameworkinfo.frameworkinfo", - "linux.iomem.iomem", - "linux.pstree.pstree", - "windows.devicetree.devicetree", - "windows.mbrscan.mbrscan", - "windows.mftscan.mftscan", - "windows.pstree.pstree", - "windows.registry.userassist.userassist", -] +PLUGIN_WITH_CHILDREN = { + "frameworkinfo.frameworkinfo": "Data", + "linux.iomem.iomem": "Name", + "linux.pstree.pstree": "PID", + "windows.devicetree.devicetree": "Offset", + "windows.mbrscan.mbrscan": "Potential MBR at Physical Offset", + "windows.mftscan.mftscan": "Offset", + "windows.pstree.pstree": "PID", + "windows.registry.userassist.userassist": "Hive Offset", +} INDEX_VALUES_LIST = [ "folder__name", @@ -270,7 +269,7 @@ def plugin(request): ) result.result = RESULT_STATUS_RUNNING - request.description = None + result.description = None result.parameter = params result.save() @@ -410,7 +409,11 @@ def generate(request): result = s.execute() # ANNOTATE RESULTS WITH INDEX NAME - info = [(hit.to_dict(), hit.meta.index.split("_")[0]) for hit in result] + info = [ + (hit.to_dict(), hit.meta.index.split("_")[0]) + for hit in result + if hit.meta.index.split("_")[0] != ".kibana" + ] try: _ = Service.objects.get(name=SERVICE_MISP) @@ -454,6 +457,29 @@ def generate(request): raise Http404("404") +def change_keys(obj, title): + """Change keys for tree rendering""" + if isinstance(obj, dict): + new = {} + for k, v in obj.items(): + if k in SYSTEM_COLUMNS: + continue + elif k == "__children": + if v != []: + new["children"] = change_keys(v, title) + else: + continue + elif k == title: + new["title"] = v + else: + new[k] = v or "-" + elif isinstance(obj, list): + new = [change_keys(v, title) for v in obj] + else: + return obj + return new + + @login_required def analysis(request): """Get and transform results for selected plugin on selected indexes""" @@ -497,7 +523,7 @@ def analysis(request): ] # If table we will generate data dynamically - if plugin.name.lower() not in PLUGIN_WITH_CHILDREN: + if plugin.name.lower() not in PLUGIN_WITH_CHILDREN.keys(): columns = [] for res in results: if res.result == RESULT_STATUS_NOT_STARTED and columns == []: @@ -542,71 +568,99 @@ def analysis(request): }, ) + columns = None # SEARCH FOR ITEMS AND KEEP INDEX - indexes_list = [ + if indexes_list := [ f"{res.dump.index}_{res.plugin.name.lower()}" for res in results if res.result == RESULT_STATUS_SUCCESS - ] - - data = [] - if indexes_list: + ]: s = Search(using=es_client, index=indexes_list).extra( size=settings.MAX_ELASTIC_WINDOWS_SIZE ) result = s.execute() # ANNOTATE RESULTS WITH INDEX NAME - info = [(hit.to_dict(), hit.meta.index.split("_")[0]) for hit in result] - - for item, item_index in info: - if item_index != ".kibana": - item.update({"color": COLOR_TEMPLATE.format(colors[item_index])}) - data.append(item) - - def change_keys(obj): - if isinstance(obj, dict): - new = {} - for k, v in obj.items(): - if k in SYSTEM_COLUMNS: - continue - elif k == "__children" and v != []: - new["children"] = change_keys(v) - elif k == "PID": - new["text"] = v - elif not v: - new.setdefault("data", {})[k] = "-" - else: - new.setdefault("data", {})[k] = v - - elif isinstance(obj, list): - new = [] - for v in obj: - new.append(change_keys(v)) - else: - return obj - return new - - new_data = [change_keys(item) for item in data] - if new_data: - columns = [{"header": "PID", "value": "text", "width": 100}] + [ - {"header": x, "value": x, "width": 100} - for x in new_data[0].get("data", {}).keys() - ] - else: - columns = None + if info := [ + (hit.to_dict(), hit.meta.index.split("_")[0]) for hit in result + ]: + columns = ( + [PLUGIN_WITH_CHILDREN[plugin.name.lower()]] + + [ + x + for x in info[0][0].keys() + if x + not in SYSTEM_COLUMNS + + [PLUGIN_WITH_CHILDREN[plugin.name.lower()], "__children"] + ] + + ["color"] + ) + # If tree we will render tree and get data dynamically context = { - "data": json.dumps(new_data), - "columns": json.dumps(columns), + "columns": columns, "note": note, - "empty": not bool(new_data), + "empty": not bool(columns), "plugin": plugin.name, } - return render(request, "website/partial_pstree.html", context) + return render(request, "website/partial_tree.html", context) raise Http404("404") +@login_required +def tree(request): + es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) + + # GET DATA + plugin = request.GET.get("plugin") + indexes = request.GET.getlist("indexes[]") + + # GET PLUGIN INFO + plugin = get_object_or_404(Plugin, name=plugin) + + # GET DICT OF COLOR AND CHECK PERMISSIONS + dumps = Dump.objects.filter(index__in=indexes) + colors = {} + for dump in dumps: + if dump not in get_objects_for_user(request.user, "website.can_see"): + raise Http404("404") + colors[dump.index] = dump.color + + # GET ALL RESULTS + results = ( + Result.objects.select_related("dump", "plugin") + .filter(plugin__name=plugin, dump__index__in=indexes) + .order_by("dump__name", "plugin__name") + ) + + data = [] + # SEARCH FOR ITEMS AND KEEP INDEX + if indexes_list := [ + f"{res.dump.index}_{res.plugin.name.lower()}" + for res in results + if res.result == RESULT_STATUS_SUCCESS + ]: + s = Search(using=es_client, index=indexes_list).extra( + size=settings.MAX_ELASTIC_WINDOWS_SIZE + ) + result = s.execute() + + # column used for icon accordion + title = PLUGIN_WITH_CHILDREN[plugin.name.lower()] + + # ANNOTATE RESULTS WITH INDEX NAME + if info := [ + (hit.to_dict(), hit.meta.index.split("_")[0]) + for hit in result + if hit.meta.index.split("_")[0] != ".kibana" + ]: + for item, item_index in info: + item = change_keys(item, title) + item["color"] = colors[item_index] + data.append(item) + return JsonResponse(data, safe=False) + + ############################## # SPECIAL VIEWER ############################## @@ -625,13 +679,13 @@ def maxmind(request): data = {} if Path("/maxmind/GeoLite2-ASN.mmdb").exists(): with geoip2.database.Reader("/maxmind/GeoLite2-ASN.mmdb") as reader: - data.update(reader.asn(ip).raw) + data |= reader.asn(ip).raw if Path("/maxmind/GeoLite2-City.mmdb").exists(): with geoip2.database.Reader("/maxmind/GeoLite2-City.mmdb") as reader: - data.update(reader.city(ip).raw) + data |= reader.city(ip).raw if Path("/maxmind/GeoLite2-Country.mmdb").exists(): with geoip2.database.Reader("/maxmind/GeoLite2-Country.mmdb") as reader: - data.update(reader.country(ip).raw) + data |= reader.country(ip).raw return render( request, "website/partial_json.html", @@ -859,12 +913,11 @@ def export(request): event.add_object(file_obj) es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) - s = ( + if s := ( Search(using=es_client, index=f"{index}_{plugin}") .query({"match": {"down_path": filepath}}) .execute() - ) - if s: + ): s = s[0].to_dict() # ADD CLAMAV SIGNATURE @@ -1401,24 +1454,23 @@ def iterate_symbols(request): k = k.decode("utf-8") except AttributeError: k = str(k) - if search: - if str(k).find(search) == -1 and str(v).find(search) == -1: - continue + if search and (search not in k and search not in str(v)): + continue - if str(v).find("file://") != -1: + if "file://" in str(v): path = ( str(v) .replace("file://", "") .replace(settings.VOLATILITY_SYMBOL_PATH, "") ) action = "" - if str(v).find("/added/") != -1: + if "/added/" in str(v): action = f"" else: path = str(v) action = f"" - symbols.append((str(k), path, action)) + symbols.append((k, path, action)) return_data = { "recordsTotal": len(banner.keys()), @@ -1493,8 +1545,7 @@ def reload_symbols(request): # Try to reload banner from elastic if first time was not successful if not dump.banner: banner = dump.result_set.get(plugin__name="banners.Banners") - banner_result = get_banner(banner) - if banner_result: + if banner_result := get_banner(banner): dump.banner = banner_result.strip("\"'") dump.save() diff --git a/requirements/base.txt b/requirements/base.txt index 4f6bbc48..f26da260 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,7 +7,7 @@ argon2-cffi==23.1.0 # https://github.com/evansd/whitenoise whitenoise==6.6.0 # https://github.com/andymccurdy/redis-py -redis==5.0.2 +redis==5.0.3 # https://github.com/redis/hiredis-py hiredis==2.3.2 # https://github.com/psycopg/psycopg2 @@ -79,9 +79,9 @@ luqum==0.13.0 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.2.1 +dask==2024.3.0 # https://github.com/dask/distributed -distributed==2024.2.1 +distributed==2024.3.0 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.0.8 # https://github.com/python-lz4/python-lz4 @@ -99,7 +99,7 @@ tornado==6.4 # ------------------------------------------------------------------------------ # https://github.com/volatilityfoundation/ # volatility3==2.5.0 -volatility3 @ git+https://github.com/volatilityfoundation/volatility3.git@110d9bef4ad36dfef80647df289e50f1f9701eb8#egg=volatility3 +volatility3 @ git+https://github.com/volatilityfoundation/volatility3.git@6f3091c644f37044d2de4edefc0eb8b5e040485d#egg=volatility3 # https://github.com/VirusTotal/yara-python #yara-python==4.1.0 # https://github.com/Viicos/clamdpy @@ -107,7 +107,7 @@ clamdpy==0.1.0.post1 # https://github.com/VirusTotal/vt-py vt-py==0.18.0 # https://github.com/mkorman90/regipy/ -regipy==4.0.0 +regipy==4.1.1 # http://www.capstone-engine.org/ capstone==5.0.1 # https://github.com/Julian/jsonschema @@ -138,7 +138,7 @@ pefile==2023.2.7 # misp export # ------------------------------------------------------------------------------ # https://github.com/MISP/PyMISP -pymisp==2.4.186 +pymisp==2.4.187 # ldap # ------------------------------------------------------------------------------ diff --git a/requirements/local.txt b/requirements/local.txt index ea6f982b..7e6f308f 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -3,7 +3,7 @@ # Testing # ------------------------------------------------------------------------------ # https://github.com/python/mypy -mypy==1.8.0 +mypy==1.9.0 # https://github.com/typeddjango/django-stubs django-stubs==4.2.7 # https://github.com/pytest-dev/pytest From 38c132c8c5efd7a58f64be721ee290611a9be68e Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Mon, 18 Mar 2024 08:40:31 +0100 Subject: [PATCH 21/84] fix download dump error --- orochi/templates/website/partial_indices.html | 2 +- orochi/website/views.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/orochi/templates/website/partial_indices.html b/orochi/templates/website/partial_indices.html index a083804c..64fe6578 100644 --- a/orochi/templates/website/partial_indices.html +++ b/orochi/templates/website/partial_indices.html @@ -1,7 +1,7 @@ {% load custom_tags %} {% if dumps %} diff --git a/orochi/website/views.py b/orochi/website/views.py index 1c616f5c..c108a7ad 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -114,6 +114,7 @@ "color", "operating_system", "author", + "upload", "status", "description", ] From 297640ddab4c3f01e27f52278da2c59d27f73bd8 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 19 Mar 2024 10:13:01 +0100 Subject: [PATCH 22/84] keep pip for volatility for shared install path --- .pre-commit-config.yaml | 2 +- compose/local/dask/Dockerfile | 5 +- compose/local/django/Dockerfile | 3 +- compose/local/django/start | 2 +- compose/local/nginx/conf/default.conf | 4 + orochi/templates/users/user_plugins.html | 17 +- orochi/utils/plugin_install.py | 3 +- orochi/utils/volatility_dask_elk.py | 12 +- orochi/website/api/serializers.py | 1 - orochi/website/views.py | 451 +++++++++++------------ requirements/base.txt | 9 +- requirements/local.txt | 2 +- 12 files changed, 264 insertions(+), 247 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fce097c6..d3dd7a4d 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-yaml - repo: https://github.com/psf/black - rev: 24.2.0 + rev: 24.3.0 hooks: - id: black diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 9ee626df..252c37f0 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.3.0-py3.12 +FROM daskdev/dask:2024.3.1-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -47,7 +47,8 @@ RUN python setup.py build \ # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.21 && uv pip install --system --no-cache -r /requirements/base.txt +RUN pip install uv==0.1.21 -e git+https://github.com/volatilityfoundation/volatility3.git@55dd39f2ba60ffdd2126b7ea011940f0df42815a#egg=volatility3 \ + && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh RUN chmod +x /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 88e9e43b..31dc026a 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -65,7 +65,8 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.21 && uv pip install --no-cache --system -r /requirements/base.txt +RUN pip install uv==0.1.21 -e git+https://github.com/volatilityfoundation/volatility3.git@55dd39f2ba60ffdd2126b7ea011940f0df42815a#egg=volatility3 \ + && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/compose/local/django/start b/compose/local/django/start index ee6bcbfd..1fc4406f 100644 --- a/compose/local/django/start +++ b/compose/local/django/start @@ -7,4 +7,4 @@ set -o nounset python manage.py makemigrations python manage.py migrate python manage.py collectstatic --skip-checks --noinput --clear -gunicorn config.wsgi:application --workers=2 -b :8000 +gunicorn config.wsgi:application --workers=2 --timeout 1800 -b :8000 diff --git a/compose/local/nginx/conf/default.conf b/compose/local/nginx/conf/default.conf index 7a105d90..ae114825 100644 --- a/compose/local/nginx/conf/default.conf +++ b/compose/local/nginx/conf/default.conf @@ -22,6 +22,10 @@ server { listen 443 ssl; listen [::]:443 ssl; + proxy_connect_timeout 50000; + proxy_read_timeout 50000; + proxy_send_timeout 50000; + server_name orochi.dev; location = /favicon.ico { access_log off; log_not_found off; } diff --git a/orochi/templates/users/user_plugins.html b/orochi/templates/users/user_plugins.html index caf19ae1..bd9998b1 100644 --- a/orochi/templates/users/user_plugins.html +++ b/orochi/templates/users/user_plugins.html @@ -184,8 +184,21 @@ data: { 'plugin': plugin_url, 'operating_system': operating_system, 'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken").val() }, method: 'post', dataType: 'json', - success: function (data) { }, - error: function () { } + success: function (data) { + $.toast({ + title: 'Plugin status!', + content: 'Plugin installed.', + type: 'success', + delay: 5000 + }); }, + error: function () { + $.toast({ + title: 'Plugin status!', + content: 'Error during plugin install.', + type: 'error', + delay: 5000 + }); + } }); }) diff --git a/orochi/utils/plugin_install.py b/orochi/utils/plugin_install.py index c98fe2c5..8c8931a9 100644 --- a/orochi/utils/plugin_install.py +++ b/orochi/utils/plugin_install.py @@ -54,4 +54,5 @@ def install_process(bash_script, reqs_script, tmp_folder): for available_plugin in available_plugins: if available_plugin.startswith(f"custom.{py_name}"): plugin_name = available_plugin - return plugin_name + return plugin_name + return None diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index 4f0f141b..4f010840 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -12,7 +12,7 @@ import traceback import uuid from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Tuple from urllib.request import pathname2url import attr @@ -585,7 +585,7 @@ def get_path_from_banner(banner): ): down_url = f"{url}{link.get('href')}" return [down_url] - except: + except Exception: return ["[Download fail] insert here symbols url!"] # DEBIAN @@ -617,10 +617,10 @@ def get_path_from_banner(banner): ): down_url = f"{url}{href}" return [down_url] - except: + except Exception: print(href.split("_")) return ["[Download fail] insert here symbols url!"] - except: + except Exception: return ["[Download fail] insert here symbols url!"] else: return ["[OS wip] insert here symbols url!"] @@ -707,13 +707,13 @@ def check_runnable(dump_pk, operating_system, banner): def refresh_symbols(): """Refresh symbols cache""" - logging.debug(f"[Refresh Symbol Cache] Started") + logging.debug("[Refresh Symbol Cache] Started") identifiers_path = os.path.join( constants.CACHE_PATH, constants.IDENTIFIERS_FILENAME ) cache = symbol_cache.SqliteCache(identifiers_path) cache.update(cli.MuteProgress()) - logging.debug(f"[Refresh Symbol Cache] Completed") + logging.debug("[Refresh Symbol Cache] Completed") def unzip_then_run(dump_pk, user_pk, password, restart, move): diff --git a/orochi/website/api/serializers.py b/orochi/website/api/serializers.py index cc0c0356..6779e020 100644 --- a/orochi/website/api/serializers.py +++ b/orochi/website/api/serializers.py @@ -1,5 +1,4 @@ from django.conf import settings -from django.contrib.sites.models import Site from rest_framework import serializers from rest_framework_nested.serializers import NestedHyperlinkedModelSerializer diff --git a/orochi/website/views.py b/orochi/website/views.py index c108a7ad..1106c1bc 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -171,7 +171,7 @@ def plugins(request): dumps = Dump.objects.filter(index__in=indexes) for dump in dumps: if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) results = ( Result.objects.filter(dump__index__in=indexes) .order_by("plugin__name") @@ -179,7 +179,7 @@ def plugins(request): .values_list("plugin__name", "plugin__comment") ) return render(request, "website/partial_plugins.html", {"results": results}) - raise Http404("404") + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) def plugin_f_and_f(dump, plugin, params, user_pk=None): @@ -199,7 +199,7 @@ def enable_plugin(request): up.automatic = enable == "true" up.save() return JsonResponse({"ok": True}) - raise Http404("404") + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) def handle_uploaded_file(index, plugin, f): @@ -217,72 +217,67 @@ def handle_uploaded_file(index, plugin, f): @user_passes_test(is_not_readonly) def plugin(request): """Prepares for plugin resubmission on selected index with/without parameters""" - if request.method == "POST": - - indexes = request.POST.get("selected_indexes").split(",") - plugin = get_object_or_404(Plugin, name=request.POST.get("selected_plugin")) - get_object_or_404(UserPlugin, plugin=plugin, user=request.user) - - for index in indexes: - dump = get_object_or_404(Dump, index=index) - if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") - - result = get_object_or_404(Result, dump=dump, plugin=plugin) - - params = {} - - parameters = get_parameters(plugin.name) - for parameter in parameters: - if parameter["name"] in request.POST.keys(): - if parameter["mode"] == "list": - value = shlex.shlex( - request.POST.get(parameter["name"]), posix=True - ) - value.whitespace += "," - value.whitespace_split = True - value = list(value) - if parameter["type"] == int: - value = [int(x) for x in value] - params[parameter["name"]] = value - - elif parameter["type"] == bool: - params[parameter["name"]] = request.POST.get( - parameter["name"] - ) in [ - "true", - "on", - ] + if request.method != "POST": + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) + indexes = request.POST.get("selected_indexes").split(",") + plugin = get_object_or_404(Plugin, name=request.POST.get("selected_plugin")) + get_object_or_404(UserPlugin, plugin=plugin, user=request.user) - else: - params[parameter["name"]] = request.POST.get(parameter["name"]) + for index in indexes: + dump = get_object_or_404(Dump, index=index) + if dump not in get_objects_for_user(request.user, "website.can_see"): + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) + + result = get_object_or_404(Result, dump=dump, plugin=plugin) + + params = {} + + parameters = get_parameters(plugin.name) + for parameter in parameters: + if parameter["name"] in request.POST.keys(): + if parameter["mode"] == "list": + value = shlex.shlex(request.POST.get(parameter["name"]), posix=True) + value.whitespace += "," + value.whitespace_split = True + value = list(value) + if parameter["type"] == int: + value = [int(x) for x in value] + params[parameter["name"]] = value + + elif parameter["type"] == bool: + params[parameter["name"]] = request.POST.get(parameter["name"]) in [ + "true", + "on", + ] - for filename in request.FILES: - filepath = handle_uploaded_file( - dump.index, plugin.name, request.FILES.get(filename) - ) - params[filename] = f"file:{pathname2url(filepath)}" + else: + params[parameter["name"]] = request.POST.get(parameter["name"]) - # REMOVE OLD DATA - es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) - es_client.indices.delete( - index=f"{dump.index}_{plugin.name.lower()}", ignore=[400, 404] + for filename in request.FILES: + filepath = handle_uploaded_file( + dump.index, plugin.name, request.FILES.get(filename) ) + params[filename] = f"file:{pathname2url(filepath)}" - result.result = RESULT_STATUS_RUNNING - result.description = None - result.parameter = params - result.save() - - plugin_f_and_f(dump, plugin, params, request.user.pk) - return JsonResponse( - { - "ok": True, - "plugin": plugin.name, - "names": request.POST.get("selected_names").split(","), - } + # REMOVE OLD DATA + es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) + es_client.indices.delete( + index=f"{dump.index}_{plugin.name.lower()}", ignore=[400, 404] ) - raise Http404("404") + + result.result = RESULT_STATUS_RUNNING + result.description = None + result.parameter = params + result.save() + + plugin_f_and_f(dump, plugin, params, request.user.pk) + return JsonResponse( + { + "ok": True, + "plugin": plugin.name, + "names": request.POST.get("selected_names").split(","), + } + ) @login_required @@ -323,15 +318,15 @@ def install_plugin(request): f = NamedTemporaryFile(mode="wb", suffix=".zip", delete=False) f.write(r.content) f.close() - plugin_name = plugin_install(f.name) - Plugin( - name=plugin_name, - operating_system=operating_system, - local=True, - local_date=datetime.now(), - ) - return JsonResponse({"ok": True}) - return Http404 + if plugin_name := plugin_install(f.name): + Plugin( + name=plugin_name, + operating_system=operating_system, + local=True, + local_date=datetime.now(), + ) + return JsonResponse({"ok": True}) + return JsonResponse({"status_code": 404, "error": "Issues installing plugin"}) ############################## @@ -340,122 +335,122 @@ def install_plugin(request): @login_required def generate(request): """Sliced data request for analysis ajax datatables request""" - if request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest": - ui_columns = request.GET.getlist("columns[]") - draw = request.GET.get("draw") + if request.META.get("HTTP_X_REQUESTED_WITH") != "XMLHttpRequest": + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) + ui_columns = request.GET.getlist("columns[]") + draw = request.GET.get("draw") - if ui_columns == ["Loading"]: - return JsonResponse( - { - "draw": draw, - "recordsTotal": 1, - "recordsFiltered": 1, - "data": [["Please wait"]], - } - ) - elif ui_columns == ["Empty"]: - return JsonResponse( - { - "draw": draw, - "recordsTotal": 1, - "recordsFiltered": 1, - "data": [["Empty data"]], - } - ) - - es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) + if ui_columns == ["Loading"]: + return JsonResponse( + { + "draw": draw, + "recordsTotal": 1, + "recordsFiltered": 1, + "data": [["Please wait"]], + } + ) + elif ui_columns == ["Empty"]: + return JsonResponse( + { + "draw": draw, + "recordsTotal": 1, + "recordsFiltered": 1, + "data": [["Empty data"]], + } + ) - # GET DATA - indexes = request.GET.getlist("indexes[]") - plugin = request.GET.get("plugin") - start = int(request.GET.get("start")) - length = int(request.GET.get("length")) - search = request.GET.get("search[value]") + es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) - # GET PLUGIN INFO - plugin = get_object_or_404(Plugin, name=plugin) + # GET DATA + indexes = request.GET.getlist("indexes[]") + plugin = request.GET.get("plugin") + start = int(request.GET.get("start")) + length = int(request.GET.get("length")) + search = request.GET.get("search[value]") - # GET DICT OF COLOR AND CHECK PERMISSIONS - dumps = Dump.objects.filter(index__in=indexes) - colors = {} - for dump in dumps: - if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") - colors[dump.index] = dump.color + # GET PLUGIN INFO + plugin = get_object_or_404(Plugin, name=plugin) - # GET ALL RESULTS - results = ( - Result.objects.select_related("dump", "plugin") - .filter(plugin__name=plugin, dump__index__in=indexes) - .order_by("dump__name", "plugin__name") - ) + # GET DICT OF COLOR AND CHECK PERMISSIONS + dumps = Dump.objects.filter(index__in=indexes) + colors = {} + for dump in dumps: + if dump not in get_objects_for_user(request.user, "website.can_see"): + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) + colors[dump.index] = dump.color - # SEARCH FOR ITEMS AND KEEP INDEX - indexes_list = [ - f"{res.dump.index}_{res.plugin.name.lower()}" - for res in results - if res.result == RESULT_STATUS_SUCCESS - ] + # GET ALL RESULTS + results = ( + Result.objects.select_related("dump", "plugin") + .filter(plugin__name=plugin, dump__index__in=indexes) + .order_by("dump__name", "plugin__name") + ) - data = [] - filtered = 0 - total = 0 - if indexes_list: - s = Search(using=es_client, index=indexes_list).extra(track_total_hits=True) - total = s.count() - if search: - s = s.query("simple_query_string", query=search) - filtered = s.count() - s = s[start : start + length] - result = s.execute() + # SEARCH FOR ITEMS AND KEEP INDEX + indexes_list = [ + f"{res.dump.index}_{res.plugin.name.lower()}" + for res in results + if res.result == RESULT_STATUS_SUCCESS + ] - # ANNOTATE RESULTS WITH INDEX NAME - info = [ - (hit.to_dict(), hit.meta.index.split("_")[0]) - for hit in result - if hit.meta.index.split("_")[0] != ".kibana" - ] + data = [] + filtered = 0 + total = 0 + if indexes_list: + s = Search(using=es_client, index=indexes_list).extra(track_total_hits=True) + total = s.count() + if search: + s = s.query("simple_query_string", query=search) + filtered = s.count() + s = s[start : start + length] + result = s.execute() - try: - _ = Service.objects.get(name=SERVICE_MISP) - misp_configured = True - except Service.DoesNotExist: - misp_configured = False + # ANNOTATE RESULTS WITH INDEX NAME + info = [ + (hit.to_dict(), hit.meta.index.split("_")[0]) + for hit in result + if hit.meta.index.split("_")[0] != ".kibana" + ] - # Add color and actions to each row - for item, item_index in info: - if item.get("down_path"): - item["actions"] = render_to_string( - "website/file_download.html", - { - "down_path": item["down_path"], - "misp_configured": misp_configured, - "regipy": Path(f"{item['down_path']}.regipy.json").exists(), - "vt": ( - open(f"{item['down_path']}.vt.json").read() - if Path(f"{item['down_path']}.vt.json").exists() - else None - ), - }, - ) + try: + _ = Service.objects.get(name=SERVICE_MISP) + misp_configured = True + except Service.DoesNotExist: + misp_configured = False + + # Add color and actions to each row + for item, item_index in info: + if item.get("down_path"): + item["actions"] = render_to_string( + "website/file_download.html", + { + "down_path": item["down_path"], + "misp_configured": misp_configured, + "regipy": Path(f"{item['down_path']}.regipy.json").exists(), + "vt": ( + open(f"{item['down_path']}.vt.json").read() + if Path(f"{item['down_path']}.vt.json").exists() + else None + ), + }, + ) - item.update({"color": COLOR_TEMPLATE.format(colors[item_index])}) - list_row = [] - for column in ui_columns: - if column in item.keys(): - list_row.append(item[column]) - else: - list_row.append("-") - data.append(list_row) - return JsonResponse( - { - "draw": draw, - "recordsTotal": total, - "recordsFiltered": filtered, - "data": data, - } - ) - raise Http404("404") + item.update({"color": COLOR_TEMPLATE.format(colors[item_index])}) + list_row = [] + for column in ui_columns: + if column in item.keys(): + list_row.append(item[column]) + else: + list_row.append("-") + data.append(list_row) + return JsonResponse( + { + "draw": draw, + "recordsTotal": total, + "recordsFiltered": filtered, + "data": data, + } + ) def change_keys(obj, title): @@ -499,7 +494,7 @@ def analysis(request): colors = {} for dump in dumps: if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) colors[dump.index] = dump.color # GET ALL RESULTS @@ -624,7 +619,7 @@ def tree(request): colors = {} for dump in dumps: if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) colors[dump.index] = dump.color # GET ALL RESULTS @@ -733,11 +728,11 @@ def get_hex(request, index): draw = int(request.GET.get("draw", 0)) length = int(request.GET.get("length", 50)) * 16 except ValueError as e: - raise Http404("404") from e + return JsonResponse({"status_code": 404, "error": str(e)}) dump = get_object_or_404(Dump, index=index) if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) data, size = get_hex_rec(dump.upload.path, length, start) return JsonResponse( @@ -757,13 +752,13 @@ def search_hex(request, index): """Search for string in memory, return occurence following actual position""" dump = get_object_or_404(Dump, index=index) if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) findstr = request.GET.get("findstr", None) try: last = int(request.GET.get("last", None)) + 1 except ValueError as e: - raise Http404("404") from e + return JsonResponse({"status_code": 404, "error": str(e)}) with open(dump.upload.path, "r+b") as f: map_file = mmap.mmap(f.fileno(), length=0, prot=mmap.PROT_READ) @@ -862,31 +857,31 @@ def diff_view(request, index_a, index_b, plugin): @user_passes_test(is_not_readonly) def restart(request): """Restart plugin on index""" - if request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest": - dump = get_object_or_404(Dump, index=request.GET.get("index")) - with transaction.atomic(): - plugins = UserPlugin.objects.filter( - plugin__operating_system__in=[ - dump.operating_system, - "Other", - ], - user=request.user, - plugin__disabled=False, - automatic=True, - ) - if plugins.count() > 0: - plugins_id = [plugin.plugin.id for plugin in plugins] - results = Result.objects.filter(plugin__pk__in=plugins_id, dump=dump) - for result in results: - result.result = RESULT_STATUS_RUNNING - Result.objects.bulk_update(results, ["result"]) - transaction.on_commit( - lambda: index_f_and_f( - dump.pk, request.user.pk, password=None, restart=plugins_id - ) + if request.META.get("HTTP_X_REQUESTED_WITH") != "XMLHttpRequest": + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) + dump = get_object_or_404(Dump, index=request.GET.get("index")) + with transaction.atomic(): + plugins = UserPlugin.objects.filter( + plugin__operating_system__in=[ + dump.operating_system, + "Other", + ], + user=request.user, + plugin__disabled=False, + automatic=True, + ) + if plugins.count() > 0: + plugins_id = [plugin.plugin.id for plugin in plugins] + results = Result.objects.filter(plugin__pk__in=plugins_id, dump=dump) + for result in results: + result.result = RESULT_STATUS_RUNNING + Result.objects.bulk_update(results, ["result"]) + transaction.on_commit( + lambda: index_f_and_f( + dump.pk, request.user.pk, password=None, restart=plugins_id ) - return JsonResponse({"ok": True}, safe=False) - raise Http404("404") + ) + return JsonResponse({"ok": True}, safe=False) ############################## @@ -947,7 +942,7 @@ def export(request): misp.add_event(event) return JsonResponse({"success": True}) - return Http404("404") + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) ############################## @@ -1051,7 +1046,7 @@ def delete_bookmark(request): up = get_object_or_404(Bookmark, pk=bookmark, user=request.user) up.delete() return JsonResponse({"ok": True}) - raise Http404("404") + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) @login_required @@ -1064,7 +1059,7 @@ def star_bookmark(request): up.star = enable == "true" up.save() return JsonResponse({"ok": True}) - raise Http404("404") + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) @login_required @@ -1116,7 +1111,7 @@ def folder_delete(request): up = get_object_or_404(Folder, pk=folder, user=request.user) up.delete() return JsonResponse({"ok": True}) - raise Http404("404") + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) ############################## @@ -1179,7 +1174,7 @@ def edit(request): dump = get_object_or_404(Dump, index=request.GET.get("index")) if dump not in get_objects_for_user(request.user, "website.can_see"): - raise Http404("404") + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) auth_users = [ user.pk @@ -1340,17 +1335,17 @@ def create(request): @user_passes_test(is_not_readonly) def delete(request): """Delete an index""" - if request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest": - es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) - index = request.GET.get("index") - dump = Dump.objects.get(index=index) - if dump not in get_objects_for_user(request.user, "website.can_see"): - Http404("404") - dump.delete() - es_client.indices.delete(index=f"{index}*", ignore=[400, 404]) - shutil.rmtree(f"{settings.MEDIA_ROOT}/{dump.index}") - return JsonResponse({"ok": True}, safe=False) - raise Http404("404") + if request.META.get("HTTP_X_REQUESTED_WITH") != "XMLHttpRequest": + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) + es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) + index = request.GET.get("index") + dump = Dump.objects.get(index=index) + if dump not in get_objects_for_user(request.user, "website.can_see"): + return JsonResponse({"status_code": 403, "error": "Unauthorized"}) + dump.delete() + es_client.indices.delete(index=f"{index}*", ignore=[400, 404]) + shutil.rmtree(f"{settings.MEDIA_ROOT}/{dump.index}") + return JsonResponse({"ok": True}, safe=False) ############################## @@ -1534,7 +1529,7 @@ def delete_symbol(request): os.unlink(symbol_path) refresh_symbols() return JsonResponse({"ok": True}) - raise Http404("404") + return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) @login_required @@ -1573,7 +1568,9 @@ def download_isf(request): try: data = json.loads(requests.get(path).content) except Exception: - raise Http404("404") + return JsonResponse( + {"status_code": 404, "error": "Error parsing symbols"} + ) def download_file(url, path): try: @@ -1744,7 +1741,9 @@ def download_rule(request, pk): if rule.count() == 1: rule = rule.first() else: - raise Http404 + return JsonResponse( + {"status_code": 404, "error": "Error fetching default rule"} + ) if os.path.exists(rule.path): with open(rule.path, "rb") as fh: diff --git a/requirements/base.txt b/requirements/base.txt index f26da260..5903afb4 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -40,7 +40,7 @@ gunicorn==21.2.0 # Django Rest Framework # ------------------------------------------------------------------------------ # https://github.com/encode/django-rest-framework -djangorestframework==3.14.0 +djangorestframework==3.15.0 # https://github.com/adamchainz/django-cors-headers django-cors-headers==4.3.1 # https://github.com/alanjds/drf-nested-routers @@ -79,9 +79,9 @@ luqum==0.13.0 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.3.0 +dask==2024.3.1 # https://github.com/dask/distributed -distributed==2024.3.0 +distributed==2024.3.1 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.0.8 # https://github.com/python-lz4/python-lz4 @@ -98,8 +98,7 @@ tornado==6.4 # Volatility # ------------------------------------------------------------------------------ # https://github.com/volatilityfoundation/ -# volatility3==2.5.0 -volatility3 @ git+https://github.com/volatilityfoundation/volatility3.git@6f3091c644f37044d2de4edefc0eb8b5e040485d#egg=volatility3 +# -e git+https://github.com/volatilityfoundation/volatility3.git@55dd39f2ba60ffdd2126b7ea011940f0df42815a#egg=volatility3 volatility3 # https://github.com/VirusTotal/yara-python #yara-python==4.1.0 # https://github.com/Viicos/clamdpy diff --git a/requirements/local.txt b/requirements/local.txt index 7e6f308f..c619b0bb 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -20,7 +20,7 @@ flake8-isort==6.1.1 # https://github.com/nedbat/coveragepy coverage==7.4.3 # https://github.com/ambv/black -black==24.2.0 +black==24.3.0 # https://github.com/PyCQA/pylint-django pylint-django==2.5.5 # https://github.com/pre-commit/pre-commit From ab8ab7236ac70db20bb3eb0afe4f2337bc6070b5 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 19 Mar 2024 14:26:51 +0100 Subject: [PATCH 23/84] plugin add fix --- orochi/utils/plugin_install.py | 79 ++++++++++--------- .../management/commands/plugins_sync.py | 24 +++--- orochi/website/views.py | 16 ++-- 3 files changed, 62 insertions(+), 57 deletions(-) diff --git a/orochi/utils/plugin_install.py b/orochi/utils/plugin_install.py index 8c8931a9..04db9994 100644 --- a/orochi/utils/plugin_install.py +++ b/orochi/utils/plugin_install.py @@ -1,4 +1,6 @@ +import logging import os +import shutil import uuid import zipfile from pathlib import Path @@ -11,28 +13,6 @@ def plugin_install(plugin_path): - bash_script = None - reqs_script = False - py_name = None - - plugin_folder = Path(settings.VOLATILITY_PLUGIN_PATH) - tmp_folder = plugin_folder / str(uuid.uuid4()) - os.mkdir(tmp_folder) - with zipfile.ZipFile(plugin_path, "r") as f: - for name in f.namelist(): - # Read apt script, no need to persist - if name.endswith(".sh"): - bash_script = f.read(name).decode("utf-8") - # Move requirements in temp folder - elif name.lower() == "requirements.txt": - reqs_script = True - with open(tmp_folder / "requirements.txt", "wb") as reqs: - reqs.write(f.read(name)) - # keep script in custom folder - elif name.endswith(".py"): - with open(plugin_folder / name, "wb") as reqs: - reqs.write(f.read(name)) - py_name = Path(name).stem def install_process(bash_script, reqs_script, tmp_folder): if bash_script: @@ -41,18 +21,43 @@ def install_process(bash_script, reqs_script, tmp_folder): if reqs_script: os.system(f"pip install -r {tmp_folder}/requirements.txt") - # Install all on dask and workers - install_process(bash_script, reqs_script, tmp_folder) - dask_client = get_client(address="tcp://scheduler:8786") - dask_client.run(install_process, bash_script, reqs_script, tmp_folder) - - _ = contexts.Context() - _ = framework.import_files(volatility3.plugins, True) - available_plugins = framework.list_plugins() - - # after install recover name from installed plugin - for available_plugin in available_plugins: - if available_plugin.startswith(f"custom.{py_name}"): - plugin_name = available_plugin - return plugin_name - return None + try: + bash_script = None + reqs_script = False + py_name = None + plugin_folder = Path(settings.VOLATILITY_PLUGIN_PATH) + tmp_folder = plugin_folder / str(uuid.uuid4()) + os.mkdir(tmp_folder) + with zipfile.ZipFile(plugin_path, "r") as f: + for name in f.namelist(): + # Read apt script, no need to persist + if name.endswith(".sh"): + bash_script = f.read(name).decode("utf-8") + # Move requirements in temp folder + elif name.lower() == "requirements.txt": + reqs_script = True + with open(tmp_folder / "requirements.txt", "wb") as reqs: + reqs.write(f.read(name)) + # keep script in custom folder + elif name.endswith(".py"): + with open(plugin_folder / name, "wb") as reqs: + reqs.write(f.read(name)) + py_name = Path(name).stem + + # Install all on dask and workers + install_process(bash_script, reqs_script, tmp_folder) + dask_client = get_client(address="tcp://scheduler:8786") + dask_client.run(install_process, bash_script, reqs_script, tmp_folder) + shutil.rmtree(tmp_folder) + + # after install recover name from installed plugin + _ = contexts.Context() + _ = framework.import_files(volatility3.plugins, True) + plugin_names = [ + x for x in framework.list_plugins() if x.startswith(f"custom.{py_name}") + ] + logging.debug(f"Installed plugins: {','.join(plugin_names)}") + return plugin_names + except Exception as e: + logging.error(f"Error installing plugin: {e}") + return [] diff --git a/orochi/website/management/commands/plugins_sync.py b/orochi/website/management/commands/plugins_sync.py index 3ecbba84..de683c10 100644 --- a/orochi/website/management/commands/plugins_sync.py +++ b/orochi/website/management/commands/plugins_sync.py @@ -21,17 +21,19 @@ def handle(self, *args, **kwargs): installed_plugins = [x.name for x in plugins] if len(plugins) > 0: self.stdout.write( - self.style.SUCCESS( - "Plugins in db: {}".format(", ".join(installed_plugins)) - ) + self.style.SUCCESS(f'Plugins in db: {", ".join(installed_plugins)}') ) else: self.stdout.write(self.style.SUCCESS("No plugins in db")) _ = contexts.Context() _ = framework.import_files(volatility3.plugins, True) - available_plugins = framework.list_plugins() - self.stdout.write("Available Plugins: {}".format(", ".join(available_plugins))) + available_plugins = { + x: y + for x, y in framework.list_plugins().items() + if not x.startswith("volatility3.cli.") + } + self.stdout.write(f'Available Plugins: {", ".join(available_plugins)}') # If plugin doesn't exists anymore disable it for plugin in plugins: @@ -40,9 +42,7 @@ def handle(self, *args, **kwargs): plugin.save() self.stdout.write( self.style.ERROR( - "Plugin {} disabled. It is not available anymore!".format( - plugin - ) + f"Plugin {plugin} disabled. It is not available anymore!" ) ) @@ -59,7 +59,7 @@ def handle(self, *args, **kwargs): plugin = Plugin(name=plugin, operating_system="Other") plugin.comment = plugin_class.__doc__ plugin.save() - self.stdout.write(self.style.SUCCESS("Plugin {} added!".format(plugin))) + self.stdout.write(self.style.SUCCESS(f"Plugin {plugin} added!")) # Add new plugin in old dump for dump in Dump.objects.all(): @@ -71,7 +71,7 @@ def handle(self, *args, **kwargs): up.result = RESULT_STATUS_NOT_STARTED up.save() self.stdout.write( - self.style.SUCCESS("Plugin {} added to old dumps!".format(plugin)) + self.style.SUCCESS(f"Plugin {plugin} added to old dumps!") ) else: @@ -85,7 +85,5 @@ def handle(self, *args, **kwargs): up, created = UserPlugin.objects.get_or_create(user=user, plugin=plugin) if created: self.stdout.write( - self.style.SUCCESS( - "Plugin {} added to {}!".format(plugin, user) - ) + self.style.SUCCESS(f"Plugin {plugin} added to {user}!") ) diff --git a/orochi/website/views.py b/orochi/website/views.py index 1106c1bc..2acd4c63 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -318,14 +318,16 @@ def install_plugin(request): f = NamedTemporaryFile(mode="wb", suffix=".zip", delete=False) f.write(r.content) f.close() - if plugin_name := plugin_install(f.name): - Plugin( - name=plugin_name, - operating_system=operating_system, - local=True, - local_date=datetime.now(), - ) + if plugin_names := plugin_install(f.name): + for plugin_name in plugin_names: + Plugin( + name=plugin_name, + operating_system=operating_system, + local=True, + local_date=datetime.now(), + ).save() return JsonResponse({"ok": True}) + return JsonResponse({"status_code": 404, "error": "Issues installing plugin"}) return JsonResponse({"status_code": 404, "error": "Issues installing plugin"}) From 0c6a6853fb43282358f0a388c9936abf5f1f34f0 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 19 Mar 2024 15:50:03 +0100 Subject: [PATCH 24/84] plugin add fix --- orochi/website/admin.py | 3 ++- orochi/website/forms.py | 1 + orochi/website/views.py | 29 ++++++++++++++++++++++++----- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/orochi/website/admin.py b/orochi/website/admin.py index 97af26bd..196d477a 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -119,7 +119,7 @@ class PluginAdmin(FileFormAdmin): form = PluginEditAdminForm add_form = PluginCreateAdminForm - list_display = ("name", "comment", "operating_system", "disabled") + list_display = ("name", "comment", "operating_system", "disabled", "local") list_filter = ( "disabled", "operating_system", @@ -127,6 +127,7 @@ class PluginAdmin(FileFormAdmin): "vt_check", "clamav_check", "regipy_check", + "local", ) search_fields = ("name",) diff --git a/orochi/website/forms.py b/orochi/website/forms.py index c3c1da28..bec06437 100644 --- a/orochi/website/forms.py +++ b/orochi/website/forms.py @@ -242,4 +242,5 @@ class Meta: "vt_check", "clamav_check", "regipy_check", + "local", ] diff --git a/orochi/website/views.py b/orochi/website/views.py index 2acd4c63..216a89c1 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -313,6 +313,14 @@ def install_plugin(request): """Install plugin from url""" plugin_path = request.POST.get("plugin") operating_system = request.POST.get("operating_system") + try: + operating_system = operating_system.capitalize() + if operating_system not in ["Linux", "Windows", "Others"]: + return JsonResponse( + {"status_code": 404, "error": "Issues installing plugin"} + ) + except Exception: + return JsonResponse({"status_code": 404, "error": "Issues installing plugin"}) r = requests.get(plugin_path, allow_redirects=True) if r.ok: f = NamedTemporaryFile(mode="wb", suffix=".zip", delete=False) @@ -320,12 +328,23 @@ def install_plugin(request): f.close() if plugin_names := plugin_install(f.name): for plugin_name in plugin_names: - Plugin( + plugin, _ = Plugin.objects.update_or_create( name=plugin_name, - operating_system=operating_system, - local=True, - local_date=datetime.now(), - ).save() + defaults={ + "operating_system": operating_system, + "local": True, + "local_date": datetime.now(), + }, + ) + for user in get_user_model().objects.all(): + UserPlugin.objects.get_or_create(user=user, plugin=plugin) + for dump in Dump.objects.all(): + if operating_system in [dump.operating_system, "Other"]: + Result.objects.update_or_create( + dump=dump, + plugin=plugin, + defaults={"result": RESULT_STATUS_NOT_STARTED}, + ) return JsonResponse({"ok": True}) return JsonResponse({"status_code": 404, "error": "Issues installing plugin"}) return JsonResponse({"status_code": 404, "error": "Issues installing plugin"}) From 4aabe0645850ee0136d41c1a27fda58239153cf0 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 21 Mar 2024 15:37:24 +0100 Subject: [PATCH 25/84] improve plugin install, regipy plugins --- orochi/templates/base.html | 12 +-- orochi/templates/website/index.html | 1 + orochi/templates/website/partial_folder.html | 2 +- orochi/templates/website/partial_info.html | 80 ++++++++++++++----- orochi/utils/plugin_install.py | 6 +- orochi/utils/volatility_dask_elk.py | 68 ++++++++++++---- orochi/website/forms.py | 34 +++++--- .../migrations/0054_dump_regipy_plugins.py | 25 ++++++ orochi/website/models.py | 3 + orochi/website/views.py | 6 +- requirements/base.txt | 2 +- 11 files changed, 184 insertions(+), 55 deletions(-) create mode 100644 orochi/website/migrations/0054_dump_regipy_plugins.py diff --git a/orochi/templates/base.html b/orochi/templates/base.html index ccba01be..70c59b71 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -204,12 +204,14 @@ // TASK STATUS setInterval(function () { - $.get("{% url 'website:dask_status' %}").done( - function (data) { + $.ajax({ + url: "{% url 'website:dask_status' %}", + success: function (data) { $("#tasks_running").html(data.running); - } - ) - }, 5000); + }, + timeout: 2000 + }); + }, 10000); // ABOUT $(document).on("click", "#about", function () { diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index 29beec51..1ea55af1 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -716,6 +716,7 @@
    History Log
    }); update_sidebar(); update_main_stage(); + selected_plugin = null; $.toast({ title: 'Index delete!', content: 'Index has been deleted successfully.', diff --git a/orochi/templates/website/partial_folder.html b/orochi/templates/website/partial_folder.html index d5bccc09..272ea6ec 100644 --- a/orochi/templates/website/partial_folder.html +++ b/orochi/templates/website/partial_folder.html @@ -4,7 +4,7 @@ {{ form.media }} {% csrf_token %} {% endfor %} diff --git a/orochi/website/views.py b/orochi/website/views.py index 94cccfed..185c63a7 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -1226,6 +1226,7 @@ def index_f_and_f(dump_pk, user_pk, password=None, restart=None, move=True): def create(request): """Manage new index creation""" data = {} + errors = None if request.method == "POST": form = DumpForm(current_user=request.user, data=request.POST) @@ -1316,7 +1317,6 @@ def create(request): data["form_is_valid"] = False else: form = DumpForm(current_user=request.user) - errors = None context = {"form": form, "errors": errors} data["html_form"] = render_to_string( From 2472e7396a8508811643a405069c25f8ea5ea852 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Fri, 5 Apr 2024 22:03:18 +0200 Subject: [PATCH 46/84] update libs, fix small issue --- compose/local/dask/Dockerfile | 4 +-- compose/local/dask/daskworkerinit.py | 9 +++++-- compose/local/django/Dockerfile | 2 +- config/settings/base.py | 1 - orochi/utils/volatility_dask_elk.py | 38 ++++++++++++++-------------- orochi/website/admin.py | 1 + orochi/website/views.py | 9 +++---- requirements/base.txt | 26 +++++++++---------- requirements/local.txt | 4 +-- 9 files changed, 49 insertions(+), 45 deletions(-) diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index f11256a2..6d345e62 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.3.1-py3.12 +FROM daskdev/dask:2024.4.1-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -47,7 +47,7 @@ RUN python setup.py build \ # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.21 -e git+https://github.com/volatilityfoundation/volatility3.git@a19dfb57a68cc7efc8926d9f6e7c24e5a2dbab9d#egg=volatility3 \ +RUN pip install uv==0.1.29 -e git+https://github.com/volatilityfoundation/volatility3.git@a19dfb57a68cc7efc8926d9f6e7c24e5a2dbab9d#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh diff --git a/compose/local/dask/daskworkerinit.py b/compose/local/dask/daskworkerinit.py index 7652f70f..3c17ab4b 100644 --- a/compose/local/dask/daskworkerinit.py +++ b/compose/local/dask/daskworkerinit.py @@ -1,11 +1,16 @@ +# sourcery skip: use-fstring-for-formatting import logging import os import sys import django -logger = logging.getLogger("distributed.utils_perf") -logger.setLevel(logging.ERROR) +logger_one = logging.getLogger("distributed.preloading") +logger_one.setLevel(logging.ERROR) +logger_two = logging.getLogger("distributed.utils") +logger_two.setLevel(logging.ERROR) +logger_three = logging.getLogger("distributed.utils_perf") +logger_three.setLevel(logging.ERROR) os.environ["DATABASE_URL"] = "postgres://{}:{}@{}:{}/{}".format( os.environ["POSTGRES_USER"], diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 4739261e..7437a999 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -65,7 +65,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.21 -e git+https://github.com/volatilityfoundation/volatility3.git@a19dfb57a68cc7efc8926d9f6e7c24e5a2dbab9d#egg=volatility3 \ +RUN pip install uv==0.1.29 -e git+https://github.com/volatilityfoundation/volatility3.git@a19dfb57a68cc7efc8926d9f6e7c24e5a2dbab9d#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/config/settings/base.py b/config/settings/base.py index 6bbc26c4..d285b5ef 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -67,7 +67,6 @@ "django_file_form", "guardian", "widget_tweaks", - "django_json_widget", "django_admin_listfilter_dropdown", "django_admin_multiple_choice_list_filter", ] diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index de75b099..32befb16 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -19,6 +19,7 @@ import elasticsearch import magic import requests +import volatility3.plugins import vt from asgiref.sync import sync_to_async from bs4 import BeautifulSoup @@ -34,24 +35,6 @@ ) from regipy.plugins.plugin import PLUGINS from regipy.registry import RegistryHive - -import volatility3.plugins -from orochi.website.defaults import ( - DUMP_STATUS_COMPLETED, - DUMP_STATUS_CREATED, - DUMP_STATUS_ERROR, - DUMP_STATUS_MISSING_SYMBOLS, - DUMP_STATUS_UNZIPPING, - RESULT_STATUS_DISABLED, - RESULT_STATUS_EMPTY, - RESULT_STATUS_ERROR, - RESULT_STATUS_NOT_STARTED, - RESULT_STATUS_RUNNING, - RESULT_STATUS_SUCCESS, - RESULT_STATUS_UNSATISFIED, - SERVICE_VIRUSTOTAL, -) -from orochi.website.models import CustomRule, Dump, Result, Service from volatility3 import cli, framework from volatility3.cli.text_renderer import ( JsonRenderer, @@ -78,6 +61,23 @@ ListRequirement, ) +from orochi.website.defaults import ( + DUMP_STATUS_COMPLETED, + DUMP_STATUS_CREATED, + DUMP_STATUS_ERROR, + DUMP_STATUS_MISSING_SYMBOLS, + DUMP_STATUS_UNZIPPING, + RESULT_STATUS_DISABLED, + RESULT_STATUS_EMPTY, + RESULT_STATUS_ERROR, + RESULT_STATUS_NOT_STARTED, + RESULT_STATUS_RUNNING, + RESULT_STATUS_SUCCESS, + RESULT_STATUS_UNSATISFIED, + SERVICE_VIRUSTOTAL, +) +from orochi.website.models import CustomRule, Dump, Result, Service + BANNER_REGEX = r'^"?Linux version (?P\S+) (?P.+) \(((?Pgcc.+)) #(?P\d+)(?P.+)$"?' COLOR_TIMELINER = { @@ -492,7 +492,7 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None, regipy_plugins=F # CALCOLATE HASH AND CHECK FOR CLAMAV SIGNATURE for x in json_data: - filename = x["File output"].replace('"', "") + filename = x.get("File output", "").replace('"', "") down_path = f"{local_path}/{filename}" if os.path.exists(down_path) and not os.path.isdir(down_path): x["down_path"] = down_path diff --git a/orochi/website/admin.py b/orochi/website/admin.py index f3ef4750..c16a30b5 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -68,6 +68,7 @@ class DumpAdmin(GuardedModelAdmin): list_display = ("name", "author", "index", "status") search_fields = ["author__name", "name", "index"] list_filter = ("author", "status", "created_at") + exclude = ("suggested_symbols_path", "regipy_plugins", "banner") def get_queryset(self, request): return super(DumpAdmin, self).get_queryset(request).prefetch_related("plugins") diff --git a/orochi/website/views.py b/orochi/website/views.py index 185c63a7..8ab0039e 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -39,6 +39,7 @@ from guardian.shortcuts import assign_perm, get_objects_for_user, get_perms, remove_perm from pymisp import MISPEvent, MISPObject, PyMISP from pymisp.tools import FileObject +from volatility3.framework import automagic, contexts from orochi.utils.download_symbols import Downloader from orochi.utils.plugin_install import plugin_install @@ -84,7 +85,6 @@ Service, UserPlugin, ) -from volatility3.framework import automagic, contexts COLOR_TEMPLATE = """ Date: Fri, 5 Apr 2024 23:10:24 +0200 Subject: [PATCH 47/84] update libs, fix small issue --- orochi/utils/volatility_dask_elk.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index 32befb16..c0fd6cf6 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -492,20 +492,20 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None, regipy_plugins=F # CALCOLATE HASH AND CHECK FOR CLAMAV SIGNATURE for x in json_data: - filename = x.get("File output", "").replace('"', "") - down_path = f"{local_path}/{filename}" - if os.path.exists(down_path) and not os.path.isdir(down_path): - x["down_path"] = down_path - x["sha256"], x["md5"] = hash_checksum(down_path) - if plugin_obj.clamav_check: - x["clamav"] = next( - ( - res.reason - for res in match - if str(res.path) == down_path - ), - "-", - ) + if filename := x.get("File output"): + down_path = f"{local_path}/{filename}" + if os.path.exists(down_path) and not os.path.isdir(down_path): + x["down_path"] = down_path + x["sha256"], x["md5"] = hash_checksum(down_path) + if plugin_obj.clamav_check: + x["clamav"] = next( + ( + res.reason + for res in match + if str(res.path) == down_path + ), + "-", + ) es = Elasticsearch( [settings.ELASTICSEARCH_URL], From be1953935189f1968e610d28f07b19cdbdceda1e Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 9 Apr 2024 13:44:40 +0200 Subject: [PATCH 48/84] #1073 wip --- .pre-commit-config.yaml | 5 + orochi/api/models.py | 34 +- orochi/api/routers/dumps.py | 52 +- orochi/api/routers/folders.py | 52 +- orochi/api/routers/plugins.py | 173 +- orochi/api/routers/users.py | 66 +- orochi/static/README.txt | 4 + .../js/handlebars/handlebars.runtime.js | 2563 +++++++++++++++++ orochi/static/js/handlebars/plugins.js | 28 + orochi/templates/base.html | 3 + .../templates/handlebars/plugins.handlebars | 8 + orochi/templates/users/user_plugins.html | 10 +- orochi/templates/website/index.html | 23 +- orochi/website/defaults.py | 15 +- orochi/website/models.py | 6 +- orochi/website/urls.py | 2 - orochi/website/views.py | 78 - 17 files changed, 2973 insertions(+), 149 deletions(-) create mode 100644 orochi/static/js/handlebars/handlebars.runtime.js create mode 100644 orochi/static/js/handlebars/plugins.js create mode 100644 orochi/templates/handlebars/plugins.handlebars diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d3dd7a4d..c3ac67a3 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,3 +19,8 @@ repos: rev: 5.13.2 hooks: - id: isort + + - repo: https://github.com/hadialqattan/pycln + rev: v2.4.0 + hooks: + - id: pycln diff --git a/orochi/api/models.py b/orochi/api/models.py index eec46cb0..02becbcc 100644 --- a/orochi/api/models.py +++ b/orochi/api/models.py @@ -1,11 +1,11 @@ -from datetime import datetime from typing import Dict, List, Optional from django.contrib.auth import get_user_model from django.contrib.auth.models import Group -from ninja import ModelSchema, Schema +from ninja import Field, ModelSchema, Schema from ninja.orm import create_schema +from orochi.website.defaults import OSEnum from orochi.website.models import Dump, Folder, Plugin, Result ################################################### @@ -124,6 +124,11 @@ class Meta: ] +class PluginInstallSchema(Schema): + plugin_url: str + operating_system: OSEnum + + ################################################### # Folder ################################################### @@ -192,25 +197,8 @@ class Meta: ################################################### -# Result +# Plugins [from Results] ################################################### -class PluginSmallSchema(ModelSchema): - class Meta: - model = Plugin - fields = ["name", "comment"] - - -class DumpSmallSchema(ModelSchema): - class Meta: - model = Dump - fields = ["index", "name"] - - -class ResultSmallOutSchema(ModelSchema): - plugin: PluginSmallSchema = None - dump: DumpSmallSchema = None - updated_at: datetime = None - - class Meta: - model = Result - fields = ["result", "parameter", "description"] +class ResultSmallOutSchema(Schema): + name: str = Field(..., alias="plugin__name") + comment: str = Field(..., alias="plugin__comment") diff --git a/orochi/api/routers/dumps.py b/orochi/api/routers/dumps.py index affd8f04..9f51bb8b 100644 --- a/orochi/api/routers/dumps.py +++ b/orochi/api/routers/dumps.py @@ -16,6 +16,20 @@ @router.get("/", auth=django_auth, response=List[DumpSchema]) def list_dumps(request, filters: Query[OperatingSytemFilters]): + """ + Summary: + Retrieve a list of dumps based on optional operating system filters. + + Explanation: + Returns a list of dumps accessible to the user, filtered by the specified operating system if provided and the user's permissions. + + Args: + - request: The request object. + - filters: Query object containing operating system filters. + + Returns: + - List of DumpSchema objects representing the dumps that match the criteria. + """ dumps = ( Dump.objects.all() if request.user.is_superuser @@ -28,14 +42,48 @@ def list_dumps(request, filters: Query[OperatingSytemFilters]): @router.get("/{pk}", response=DumpInfoSchema, auth=django_auth) def get_dump_info(request, pk: UUID): + """ + Summary: + Retrieve detailed information about a specific dump by its index. + + Explanation: + Fetches the dump with the specified index and returns its information if the user has permission to view it; otherwise, returns a 403 Forbidden response. + + Args: + - request: The request object. + - pk: The UUID index of the dump to retrieve information for. + + Returns: + - DumpInfoSchema object representing the detailed information of the dump. + """ dump = get_object_or_404(Dump, index=pk) if dump not in get_objects_for_user(request.user, "website.can_see"): return HttpResponse("Forbidden", status=403) return dump -@router.get("/{idxs:pks}/plugins", response=ResultSmallOutSchema, auth=django_auth) +@router.get( + "/{idxs:pks}/plugins", + url_name="dumps_plugins", + response=List[ResultSmallOutSchema], + auth=django_auth, +) def get_dump_plugins(request, pks: List[UUID], filters: Query[DumpFilters] = None): + """ + Summary: + Retrieve a list of plugins associated with specified dumps. + + Explanation: + Fetches the plugins related to the dumps identified by the provided list of UUIDs, considering user permissions, and optionally filters the results based on DumpFilters. + + Args: + - request: The request object. + - pks: List of UUIDs representing the indexes of the dumps to retrieve plugins for. + - filters: Optional Query object containing dump filters. + + Returns: + - List of ResultSmallOutSchema objects representing the plugins associated with the specified dumps. + """ dumps_ok = get_objects_for_user(request.user, "website.can_see") dumps = [ dump.index for dump in Dump.objects.filter(index__in=pks) if dump in dumps_ok @@ -44,6 +92,8 @@ def get_dump_plugins(request, pks: List[UUID], filters: Query[DumpFilters] = Non Result.objects.select_related("dump", "plugin") .filter(dump__index__in=dumps) .order_by("plugin__name") + .distinct() + .values("plugin__name", "plugin__comment") ) if filters and filters.result: res = res.filter(result=filters.result) diff --git a/orochi/api/routers/folders.py b/orochi/api/routers/folders.py index 51bc27d5..d38b389d 100644 --- a/orochi/api/routers/folders.py +++ b/orochi/api/routers/folders.py @@ -15,6 +15,19 @@ @router.get("/", auth=django_auth, response=List[FolderFullSchema]) def list_folders(request): + """ + Summary: + Retrieve a list of folders based on user permissions. + + Explanation: + Returns all folders if the user is a superuser; otherwise, returns folders associated with the current user. + + Args: + - request: The request object. + + Returns: + - List of FolderFullSchema objects representing the folders accessible to the user. + """ if request.user.is_superuser: return Folder.objects.all() return Folder.objects.filter(user=request.user) @@ -28,6 +41,20 @@ def list_folders(request): ) @ninja_test_required("is_not_readonly") def create_folder(request, folder_in: FolderSchema): + """ + Summary: + Create a new folder with the provided name. + + Explanation: + Attempts to create a new folder with the specified name for the current user. Returns the created folder if successful, or an error response if the folder already exists. + + Args: + - request: The request object. + - folder_in: FolderSchema object containing the details of the folder to be created. + + Returns: + - If successful, returns HTTP status code 201 and the created FolderFullSchema object. If the folder already exists, returns HTTP status code 400 and an ErrorsOut object with an error message. + """ try: folder = Folder.objects.create(name=folder_in.name, user=request.user) folder.save() @@ -36,8 +63,27 @@ def create_folder(request, folder_in: FolderSchema): return 400, {"errors": "Folder already exists"} -@router.delete("/{name}", auth=django_auth, response={200: SuccessResponse}) +@router.delete( + "/{str:name}", auth=django_auth, response={200: SuccessResponse, 400: ErrorsOut} +) def delete_folder(request, name: str): + """ + Summary: + Delete a folder by name with error handling. + + Explanation: + Attempts to delete the folder with the specified name belonging to the current user. Returns a success message if the deletion is successful, or an error response with details if an exception occurs during deletion. + + Args: + - request: The request object. + - name: The name of the folder to delete. + + Returns: + - If successful, returns HTTP status code 200 and a success message dictionary. If an exception occurs, returns HTTP status code 400 and an ErrorsOut object with the exception details. + """ folder = get_object_or_404(Folder, name=name, user=request.user) - folder.delete() - return 200, {"message": f"Folder {name} deleted"} + try: + folder.delete() + return 200, {"message": f"Folder {name} deleted"} + except Exception as excp: + return 400, {"errors": str(excp)} diff --git a/orochi/api/routers/plugins.py b/orochi/api/routers/plugins.py index 030ff850..5b443633 100644 --- a/orochi/api/routers/plugins.py +++ b/orochi/api/routers/plugins.py @@ -1,47 +1,186 @@ +from datetime import datetime +from tempfile import NamedTemporaryFile from typing import List +import requests +from django.contrib.auth import get_user_model from django.shortcuts import get_object_or_404 from ninja import Query, Router from ninja.security import django_auth from orochi.api.filters import OperatingSytemFilters -from orochi.api.models import PluginInSchema, PluginOutSchema, SuccessResponse -from orochi.website.models import Plugin, UserPlugin +from orochi.api.models import ( + ErrorsOut, + PluginInSchema, + PluginInstallSchema, + PluginOutSchema, + SuccessResponse, +) +from orochi.utils.plugin_install import plugin_install +from orochi.website.defaults import RESULT_STATUS_NOT_STARTED +from orochi.website.models import Dump, Plugin, Result, UserPlugin router = Router() @router.get("/", response={200: List[PluginOutSchema]}, auth=django_auth) def list_plugins(request, filters: Query[OperatingSytemFilters] = None): + """ + Summary: + Get a list of plugins based on optional operating system filters. + + Explanation: + Retrieves a list of plugins filtered by the specified operating system if provided, otherwise returns all plugins. + + Args: + - request: The request object. + - filters: Optional Query object containing operating system filters. + + Returns: + - List of PluginOutSchema objects. + + Examples: + list_plugins(request) + list_plugins(request, filters=Query(operating_system='Windows')) + """ if filters and filters.operating_system: return Plugin.objects.filter(operating_system=filters.operating_system) return Plugin.objects.all() -@router.get("/{name}", response={200: PluginOutSchema}, auth=django_auth) +@router.post( + "/install", + auth=django_auth, + url_name="install_plugin", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def install_plugin(request, plugin_info: PluginInstallSchema): + """ + Summary: + Install a plugin from the provided PluginInstallSchema. + + Explanation: + Downloads the plugin from the specified URL in the PluginInstallSchema, installs it for the specified operating system, and updates the database with the plugin information. UserPlugin and Result entries are created for all users and dumps respectively. + + Args: + - request: The request object. + - plugin_info: PluginInstallSchema object containing the plugin URL and operating system information. + + Returns: + - If successful, returns HTTP status code 200 and a success message dictionary. If installation fails, returns HTTP status code 400 and an ErrorsOut object with the error details. + """ + try: + req = requests.get(plugin_info.plugin_url, allow_redirects=True) + if req.ok: + f = NamedTemporaryFile(mode="wb", suffix=".zip", delete=False) + f.write(req.content) + f.close() + if plugin_names := plugin_install(f.name): + for plugin_data in plugin_names: + plugin_name, plugin_class = list(plugin_data.items())[0] + plugin, _ = Plugin.objects.update_or_create( + name=plugin_name, + defaults={ + "comment": plugin_class.__doc__, + "operating_system": plugin_info.operating_system, + "local": True, + "local_date": datetime.now(), + }, + ) + for user in get_user_model().objects.all(): + UserPlugin.objects.get_or_create(user=user, plugin=plugin) + for dump in Dump.objects.all(): + if plugin_info.operating_system in [ + dump.operating_system, + "Other", + ]: + Result.objects.update_or_create( + dump=dump, + plugin=plugin, + defaults={"result": RESULT_STATUS_NOT_STARTED}, + ) + return 200, {"message": "Plugin installed successfully"} + return 400, {"errors": "Failed to install plugin"} + except Exception as excp: + return 400, {"errors": str(excp)} + + +@router.get("/{str:name}", response={200: PluginOutSchema}, auth=django_auth) def get_plugin(request, name: str): - return Plugin.objects.get(name=name) + """ + Summary: + Retrieve a specific plugin by name. + + Explanation: + Fetches a plugin from the database based on the provided name. + + Args: + - request: The request object. + - name: The name of the plugin to retrieve. + Returns: + - A single PluginOutSchema object representing the retrieved plugin. + """ + return get_object_or_404(Plugin, name=name) -@router.put("/{name}", response={200: PluginOutSchema}, auth=django_auth) + +@router.put( + "/{str:name}", response={200: PluginOutSchema, 400: ErrorsOut}, auth=django_auth +) def update_plugin(request, name: str, data: PluginInSchema): + """ + Summary: + Update a plugin with new data based on the provided name. + + Explanation: + Updates the attributes of a plugin specified by the name with the data provided in the PluginInSchema object. + + Args: + - request: The request object. + - name: The name of the plugin to update. + - data: PluginInSchema object containing the new data for the plugin. + + Returns: + - Updated PluginOutSchema object representing the modified plugin. + """ plugin = get_object_or_404(Plugin, name=name) - for attr, value in data.dict().items(): - setattr(plugin, attr, value) - plugin.save() - return plugin + try: + for attr, value in data.dict().items(): + setattr(plugin, attr, value) + plugin.save() + return plugin + except Exception as excp: + return 400, {"errors": str(excp)} @router.post( - "/{name}/enable/{enable}", + "/{str:name}/enable/{enable}", auth=django_auth, url_name="enable", - response={200: SuccessResponse}, + response={200: SuccessResponse, 400: ErrorsOut}, ) def enable_plugin(request, name: str, enable: bool): - plugin = get_object_or_404(UserPlugin, plugin__name=name, user=request.user) - plugin.automatic = enable - plugin.save() - return 200, { - "message": f"Plugin {name} enabled" if enable else f"Plugin {name} disabled" - } + """ + Summary: + Enable or disable a plugin for the current user. + + Explanation: + Updates the automatic attribute of a UserPlugin associated with the specified plugin name and the current user based on the enable flag. + + Args: + - request: The request object. + - name: The name of the plugin to enable or disable. + - enable: A boolean flag indicating whether to enable (True) or disable (False) the plugin. + + Returns: + - Tuple containing HTTP status code 200 and a success message dictionary. + """ + try: + plugin = get_object_or_404(UserPlugin, plugin__name=name, user=request.user) + plugin.automatic = enable + plugin.save() + return 200, { + "message": f"Plugin {name} enabled" if enable else f"Plugin {name} disabled" + } + except Exception as excp: + return 400, {"errors": str(excp)} diff --git a/orochi/api/routers/users.py b/orochi/api/routers/users.py index 90653d45..961d91e7 100644 --- a/orochi/api/routers/users.py +++ b/orochi/api/routers/users.py @@ -15,6 +15,21 @@ @router.post("/", response={201: UserOutSchema}, auth=django_auth_superuser) def create_user(request, user_in: UserInSchema, is_readonly: bool = False): + """ + Summary: + Create a new user with optional read-only access. + + Explanation: + Creates a new user based on the provided UserInSchema data, and optionally assigns read-only permissions to the user. The user's email is verified during creation. + + Args: + - request: The request object. + - user_in: UserInSchema object containing the user details. + - is_readonly: A boolean flag indicating whether the user should have read-only access (default is False). + + Returns: + - HTTP status code 201 and the created UserOutSchema object representing the new user. + """ user = get_user_model().objects.create_user(**user_in.dict()) email, _ = EmailAddress.objects.get_or_create(user=user, email=user.email) email.verified = True @@ -28,20 +43,65 @@ def create_user(request, user_in: UserInSchema, is_readonly: bool = False): @router.get("/", response={200: List[UserOutSchema]}, auth=django_auth) @paginate def list_users(request): + """ + Summary: + Retrieve a list of users. + + Explanation: + Returns a list of all users in the system. + + Args: + - request: The request object. + + Returns: + - List of UserOutSchema objects representing the users. + """ return get_user_model().objects.all() @router.get("/me", response={200: UserOutSchema, 403: ErrorsOut}) def me(request): + """ + Summary: + Retrieve information about the authenticated user. + + Explanation: + Returns details of the authenticated user if available; otherwise, returns a 403 Forbidden response with an error message prompting the user to sign in. + + Args: + - request: The request object. + + Returns: + - If the user is authenticated, returns the UserOutSchema object representing the authenticated user. If not authenticated, returns HTTP status code 403 and an ErrorsOut object with a sign-in prompt. + """ if not request.user.is_authenticated: return 403, {"errors": "Please sign in first"} return request.user @router.delete( - "/{username}", auth=django_auth_superuser, response={200: SuccessResponse} + "/{str:username}", + auth=django_auth_superuser, + response={200: SuccessResponse, 400: ErrorsOut}, ) def delete_user(request, username: str): + """ + Summary: + Delete a user by username with error handling. + + Explanation: + Attempts to delete the user with the specified username from the system. Returns a success message if the deletion is successful, or an error response with details if an exception occurs during deletion. + + Args: + - request: The request object. + - username: The username of the user to delete. + + Returns: + - If successful, returns HTTP status code 200 and a success message dictionary. If an exception occurs, returns HTTP status code 400 and an ErrorsOut object with the exception details. + """ user = get_object_or_404(get_user_model(), username=username) - user.delete() - return 200, {"message": f"User {username} deleted"} + try: + user.delete() + return 200, {"message": f"User {username} deleted"} + except Exception as excp: + return 400, {"errors": str(excp)} diff --git a/orochi/static/README.txt b/orochi/static/README.txt index 4b083068..ae4b3062 100644 --- a/orochi/static/README.txt +++ b/orochi/static/README.txt @@ -46,3 +46,7 @@ # Marked [Changelog with MD] --> https://github.com/markedjs/marked --> version 9.1.1 + +# Handlebars [Template rendering] +--> https://handlebarsjs.com/ +--> version 4.7.8 diff --git a/orochi/static/js/handlebars/handlebars.runtime.js b/orochi/static/js/handlebars/handlebars.runtime.js new file mode 100644 index 00000000..6f76b670 --- /dev/null +++ b/orochi/static/js/handlebars/handlebars.runtime.js @@ -0,0 +1,2563 @@ +/**! + + @license + handlebars v4.7.8 + +Copyright (C) 2011-2019 by Yehuda Katz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["Handlebars"] = factory(); + else + root["Handlebars"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireWildcard = __webpack_require__(1)['default']; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + + var _handlebarsBase = __webpack_require__(3); + + var base = _interopRequireWildcard(_handlebarsBase); + + // Each of these augment the Handlebars object. No need to setup here. + // (This is done to easily share code between commonjs and browse envs) + + var _handlebarsSafeString = __webpack_require__(76); + + var _handlebarsSafeString2 = _interopRequireDefault(_handlebarsSafeString); + + var _handlebarsException = __webpack_require__(5); + + var _handlebarsException2 = _interopRequireDefault(_handlebarsException); + + var _handlebarsUtils = __webpack_require__(4); + + var Utils = _interopRequireWildcard(_handlebarsUtils); + + var _handlebarsRuntime = __webpack_require__(77); + + var runtime = _interopRequireWildcard(_handlebarsRuntime); + + var _handlebarsNoConflict = __webpack_require__(82); + + var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); + + // For compatibility and usage outside of module systems, make the Handlebars object a namespace + function create() { + var hb = new base.HandlebarsEnvironment(); + + Utils.extend(hb, base); + hb.SafeString = _handlebarsSafeString2['default']; + hb.Exception = _handlebarsException2['default']; + hb.Utils = Utils; + hb.escapeExpression = Utils.escapeExpression; + + hb.VM = runtime; + hb.template = function (spec) { + return runtime.template(spec, hb); + }; + + return hb; + } + + var inst = create(); + inst.create = create; + + _handlebarsNoConflict2['default'](inst); + + inst['default'] = inst; + + exports['default'] = inst; + module.exports = exports['default']; + +/***/ }), +/* 1 */ +/***/ (function(module, exports) { + + "use strict"; + + exports["default"] = function (obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {}; + + if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + } + + newObj["default"] = obj; + return newObj; + } + }; + + exports.__esModule = true; + +/***/ }), +/* 2 */ +/***/ (function(module, exports) { + + "use strict"; + + exports["default"] = function (obj) { + return obj && obj.__esModule ? obj : { + "default": obj + }; + }; + + exports.__esModule = true; + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + exports.HandlebarsEnvironment = HandlebarsEnvironment; + + var _utils = __webpack_require__(4); + + var _exception = __webpack_require__(5); + + var _exception2 = _interopRequireDefault(_exception); + + var _helpers = __webpack_require__(9); + + var _decorators = __webpack_require__(69); + + var _logger = __webpack_require__(71); + + var _logger2 = _interopRequireDefault(_logger); + + var _internalProtoAccess = __webpack_require__(72); + + var VERSION = '4.7.8'; + exports.VERSION = VERSION; + var COMPILER_REVISION = 8; + exports.COMPILER_REVISION = COMPILER_REVISION; + var LAST_COMPATIBLE_COMPILER_REVISION = 7; + + exports.LAST_COMPATIBLE_COMPILER_REVISION = LAST_COMPATIBLE_COMPILER_REVISION; + var REVISION_CHANGES = { + 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it + 2: '== 1.0.0-rc.3', + 3: '== 1.0.0-rc.4', + 4: '== 1.x.x', + 5: '== 2.0.0-alpha.x', + 6: '>= 2.0.0-beta.1', + 7: '>= 4.0.0 <4.3.0', + 8: '>= 4.3.0' + }; + + exports.REVISION_CHANGES = REVISION_CHANGES; + var objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials, decorators) { + this.helpers = helpers || {}; + this.partials = partials || {}; + this.decorators = decorators || {}; + + _helpers.registerDefaultHelpers(this); + _decorators.registerDefaultDecorators(this); + } + + HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: _logger2['default'], + log: _logger2['default'].log, + + registerHelper: function registerHelper(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple helpers'); + } + _utils.extend(this.helpers, name); + } else { + this.helpers[name] = fn; + } + }, + unregisterHelper: function unregisterHelper(name) { + delete this.helpers[name]; + }, + + registerPartial: function registerPartial(name, partial) { + if (_utils.toString.call(name) === objectType) { + _utils.extend(this.partials, name); + } else { + if (typeof partial === 'undefined') { + throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined'); + } + this.partials[name] = partial; + } + }, + unregisterPartial: function unregisterPartial(name) { + delete this.partials[name]; + }, + + registerDecorator: function registerDecorator(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple decorators'); + } + _utils.extend(this.decorators, name); + } else { + this.decorators[name] = fn; + } + }, + unregisterDecorator: function unregisterDecorator(name) { + delete this.decorators[name]; + }, + /** + * Reset the memory of illegal property accesses that have already been logged. + * @deprecated should only be used in handlebars test-cases + */ + resetLoggedPropertyAccesses: function resetLoggedPropertyAccesses() { + _internalProtoAccess.resetLoggedProperties(); + } + }; + + var log = _logger2['default'].log; + + exports.log = log; + exports.createFrame = _utils.createFrame; + exports.logger = _logger2['default']; + +/***/ }), +/* 4 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports.extend = extend; + exports.indexOf = indexOf; + exports.escapeExpression = escapeExpression; + exports.isEmpty = isEmpty; + exports.createFrame = createFrame; + exports.blockParams = blockParams; + exports.appendContextPath = appendContextPath; + var escape = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`', + '=': '=' + }; + + var badChars = /[&<>"'`=]/g, + possible = /[&<>"'`=]/; + + function escapeChar(chr) { + return escape[chr]; + } + + function extend(obj /* , ...source */) { + for (var i = 1; i < arguments.length; i++) { + for (var key in arguments[i]) { + if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { + obj[key] = arguments[i][key]; + } + } + } + + return obj; + } + + var toString = Object.prototype.toString; + + exports.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + /* eslint-disable func-style */ + var isFunction = function isFunction(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + /* istanbul ignore next */ + if (isFunction(/x/)) { + exports.isFunction = isFunction = function (value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; + } + exports.isFunction = isFunction; + + /* eslint-enable func-style */ + + /* istanbul ignore next */ + var isArray = Array.isArray || function (value) { + return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; + }; + + exports.isArray = isArray; + // Older IE versions do not directly support indexOf so we must implement our own, sadly. + + function indexOf(array, value) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + return -1; + } + + function escapeExpression(string) { + if (typeof string !== 'string') { + // don't escape SafeStrings, since they're already safe + if (string && string.toHTML) { + return string.toHTML(); + } else if (string == null) { + return ''; + } else if (!string) { + return string + ''; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = '' + string; + } + + if (!possible.test(string)) { + return string; + } + return string.replace(badChars, escapeChar); + } + + function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } + + function createFrame(object) { + var frame = extend({}, object); + frame._parent = object; + return frame; + } + + function blockParams(params, ids) { + params.path = ids; + return params; + } + + function appendContextPath(contextPath, id) { + return (contextPath ? contextPath + '.' : '') + id; + } + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$defineProperty = __webpack_require__(6)['default']; + + exports.__esModule = true; + var errorProps = ['description', 'fileName', 'lineNumber', 'endLineNumber', 'message', 'name', 'number', 'stack']; + + function Exception(message, node) { + var loc = node && node.loc, + line = undefined, + endLineNumber = undefined, + column = undefined, + endColumn = undefined; + + if (loc) { + line = loc.start.line; + endLineNumber = loc.end.line; + column = loc.start.column; + endColumn = loc.end.column; + + message += ' - ' + line + ':' + column; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + /* istanbul ignore else */ + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Exception); + } + + try { + if (loc) { + this.lineNumber = line; + this.endLineNumber = endLineNumber; + + // Work around issue under safari where we can't directly set the column value + /* istanbul ignore next */ + if (_Object$defineProperty) { + Object.defineProperty(this, 'column', { + value: column, + enumerable: true + }); + Object.defineProperty(this, 'endColumn', { + value: endColumn, + enumerable: true + }); + } else { + this.column = column; + this.endColumn = endColumn; + } + } + } catch (nop) { + /* Ignore if the browser is very particular */ + } + } + + Exception.prototype = new Error(); + + exports['default'] = Exception; + module.exports = exports['default']; + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(7), __esModule: true }; + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(8); + module.exports = function defineProperty(it, key, desc){ + return $.setDesc(it, key, desc); + }; + +/***/ }), +/* 8 */ +/***/ (function(module, exports) { + + var $Object = Object; + module.exports = { + create: $Object.create, + getProto: $Object.getPrototypeOf, + isEnum: {}.propertyIsEnumerable, + getDesc: $Object.getOwnPropertyDescriptor, + setDesc: $Object.defineProperty, + setDescs: $Object.defineProperties, + getKeys: $Object.keys, + getNames: $Object.getOwnPropertyNames, + getSymbols: $Object.getOwnPropertySymbols, + each: [].forEach + }; + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + exports.registerDefaultHelpers = registerDefaultHelpers; + exports.moveHelperToHooks = moveHelperToHooks; + + var _helpersBlockHelperMissing = __webpack_require__(10); + + var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing); + + var _helpersEach = __webpack_require__(11); + + var _helpersEach2 = _interopRequireDefault(_helpersEach); + + var _helpersHelperMissing = __webpack_require__(64); + + var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing); + + var _helpersIf = __webpack_require__(65); + + var _helpersIf2 = _interopRequireDefault(_helpersIf); + + var _helpersLog = __webpack_require__(66); + + var _helpersLog2 = _interopRequireDefault(_helpersLog); + + var _helpersLookup = __webpack_require__(67); + + var _helpersLookup2 = _interopRequireDefault(_helpersLookup); + + var _helpersWith = __webpack_require__(68); + + var _helpersWith2 = _interopRequireDefault(_helpersWith); + + function registerDefaultHelpers(instance) { + _helpersBlockHelperMissing2['default'](instance); + _helpersEach2['default'](instance); + _helpersHelperMissing2['default'](instance); + _helpersIf2['default'](instance); + _helpersLog2['default'](instance); + _helpersLookup2['default'](instance); + _helpersWith2['default'](instance); + } + + function moveHelperToHooks(instance, helperName, keepHelper) { + if (instance.helpers[helperName]) { + instance.hooks[helperName] = instance.helpers[helperName]; + if (!keepHelper) { + delete instance.helpers[helperName]; + } + } + } + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(4); + + exports['default'] = function (instance) { + instance.registerHelper('blockHelperMissing', function (context, options) { + var inverse = options.inverse, + fn = options.fn; + + if (context === true) { + return fn(this); + } else if (context === false || context == null) { + return inverse(this); + } else if (_utils.isArray(context)) { + if (context.length > 0) { + if (options.ids) { + options.ids = [options.name]; + } + + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + if (options.data && options.ids) { + var data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name); + options = { data: data }; + } + + return fn(context, options); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Symbol = __webpack_require__(12)['default']; + + var _Symbol$iterator = __webpack_require__(42)['default']; + + var _getIterator = __webpack_require__(54)['default']; + + var _Object$keys = __webpack_require__(59)['default']; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(4); + + var _exception = __webpack_require__(5); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('each', function (context, options) { + if (!options) { + throw new _exception2['default']('Must pass iterator to #each'); + } + + var fn = options.fn, + inverse = options.inverse, + i = 0, + ret = '', + data = undefined, + contextPath = undefined; + + if (options.data && options.ids) { + contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; + } + + if (_utils.isFunction(context)) { + context = context.call(this); + } + + if (options.data) { + data = _utils.createFrame(options.data); + } + + function execIteration(field, index, last) { + if (data) { + data.key = field; + data.index = index; + data.first = index === 0; + data.last = !!last; + + if (contextPath) { + data.contextPath = contextPath + field; + } + } + + ret = ret + fn(context[field], { + data: data, + blockParams: _utils.blockParams([context[field], field], [contextPath + field, null]) + }); + } + + if (context && typeof context === 'object') { + if (_utils.isArray(context)) { + for (var j = context.length; i < j; i++) { + if (i in context) { + execIteration(i, i, i === context.length - 1); + } + } + } else if (typeof _Symbol === 'function' && context[_Symbol$iterator]) { + var newContext = []; + var iterator = _getIterator(context); + for (var it = iterator.next(); !it.done; it = iterator.next()) { + newContext.push(it.value); + } + context = newContext; + for (var j = context.length; i < j; i++) { + execIteration(i, i, i === context.length - 1); + } + } else { + (function () { + var priorKey = undefined; + + _Object$keys(context).forEach(function (key) { + // We're running the iterations one step out of sync so we can detect + // the last iteration without have to scan the object twice and create + // an itermediate keys array. + if (priorKey !== undefined) { + execIteration(priorKey, i - 1); + } + priorKey = key; + i++; + }); + if (priorKey !== undefined) { + execIteration(priorKey, i - 1, true); + } + })(); + } + } + + if (i === 0) { + ret = inverse(this); + } + + return ret; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(13), __esModule: true }; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(14); + __webpack_require__(41); + module.exports = __webpack_require__(20).Symbol; + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + // ECMAScript 6 symbols shim + var $ = __webpack_require__(8) + , global = __webpack_require__(15) + , has = __webpack_require__(16) + , DESCRIPTORS = __webpack_require__(17) + , $export = __webpack_require__(19) + , redefine = __webpack_require__(23) + , $fails = __webpack_require__(18) + , shared = __webpack_require__(26) + , setToStringTag = __webpack_require__(27) + , uid = __webpack_require__(29) + , wks = __webpack_require__(28) + , keyOf = __webpack_require__(30) + , $names = __webpack_require__(35) + , enumKeys = __webpack_require__(36) + , isArray = __webpack_require__(37) + , anObject = __webpack_require__(38) + , toIObject = __webpack_require__(31) + , createDesc = __webpack_require__(25) + , getDesc = $.getDesc + , setDesc = $.setDesc + , _create = $.create + , getNames = $names.get + , $Symbol = global.Symbol + , $JSON = global.JSON + , _stringify = $JSON && $JSON.stringify + , setter = false + , HIDDEN = wks('_hidden') + , isEnum = $.isEnum + , SymbolRegistry = shared('symbol-registry') + , AllSymbols = shared('symbols') + , useNative = typeof $Symbol == 'function' + , ObjectProto = Object.prototype; + + // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687 + var setSymbolDesc = DESCRIPTORS && $fails(function(){ + return _create(setDesc({}, 'a', { + get: function(){ return setDesc(this, 'a', {value: 7}).a; } + })).a != 7; + }) ? function(it, key, D){ + var protoDesc = getDesc(ObjectProto, key); + if(protoDesc)delete ObjectProto[key]; + setDesc(it, key, D); + if(protoDesc && it !== ObjectProto)setDesc(ObjectProto, key, protoDesc); + } : setDesc; + + var wrap = function(tag){ + var sym = AllSymbols[tag] = _create($Symbol.prototype); + sym._k = tag; + DESCRIPTORS && setter && setSymbolDesc(ObjectProto, tag, { + configurable: true, + set: function(value){ + if(has(this, HIDDEN) && has(this[HIDDEN], tag))this[HIDDEN][tag] = false; + setSymbolDesc(this, tag, createDesc(1, value)); + } + }); + return sym; + }; + + var isSymbol = function(it){ + return typeof it == 'symbol'; + }; + + var $defineProperty = function defineProperty(it, key, D){ + if(D && has(AllSymbols, key)){ + if(!D.enumerable){ + if(!has(it, HIDDEN))setDesc(it, HIDDEN, createDesc(1, {})); + it[HIDDEN][key] = true; + } else { + if(has(it, HIDDEN) && it[HIDDEN][key])it[HIDDEN][key] = false; + D = _create(D, {enumerable: createDesc(0, false)}); + } return setSymbolDesc(it, key, D); + } return setDesc(it, key, D); + }; + var $defineProperties = function defineProperties(it, P){ + anObject(it); + var keys = enumKeys(P = toIObject(P)) + , i = 0 + , l = keys.length + , key; + while(l > i)$defineProperty(it, key = keys[i++], P[key]); + return it; + }; + var $create = function create(it, P){ + return P === undefined ? _create(it) : $defineProperties(_create(it), P); + }; + var $propertyIsEnumerable = function propertyIsEnumerable(key){ + var E = isEnum.call(this, key); + return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] + ? E : true; + }; + var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key){ + var D = getDesc(it = toIObject(it), key); + if(D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key]))D.enumerable = true; + return D; + }; + var $getOwnPropertyNames = function getOwnPropertyNames(it){ + var names = getNames(toIObject(it)) + , result = [] + , i = 0 + , key; + while(names.length > i)if(!has(AllSymbols, key = names[i++]) && key != HIDDEN)result.push(key); + return result; + }; + var $getOwnPropertySymbols = function getOwnPropertySymbols(it){ + var names = getNames(toIObject(it)) + , result = [] + , i = 0 + , key; + while(names.length > i)if(has(AllSymbols, key = names[i++]))result.push(AllSymbols[key]); + return result; + }; + var $stringify = function stringify(it){ + if(it === undefined || isSymbol(it))return; // IE8 returns string on undefined + var args = [it] + , i = 1 + , $$ = arguments + , replacer, $replacer; + while($$.length > i)args.push($$[i++]); + replacer = args[1]; + if(typeof replacer == 'function')$replacer = replacer; + if($replacer || !isArray(replacer))replacer = function(key, value){ + if($replacer)value = $replacer.call(this, key, value); + if(!isSymbol(value))return value; + }; + args[1] = replacer; + return _stringify.apply($JSON, args); + }; + var buggyJSON = $fails(function(){ + var S = $Symbol(); + // MS Edge converts symbol values to JSON as {} + // WebKit converts symbol values to JSON as null + // V8 throws on boxed symbols + return _stringify([S]) != '[null]' || _stringify({a: S}) != '{}' || _stringify(Object(S)) != '{}'; + }); + + // 19.4.1.1 Symbol([description]) + if(!useNative){ + $Symbol = function Symbol(){ + if(isSymbol(this))throw TypeError('Symbol is not a constructor'); + return wrap(uid(arguments.length > 0 ? arguments[0] : undefined)); + }; + redefine($Symbol.prototype, 'toString', function toString(){ + return this._k; + }); + + isSymbol = function(it){ + return it instanceof $Symbol; + }; + + $.create = $create; + $.isEnum = $propertyIsEnumerable; + $.getDesc = $getOwnPropertyDescriptor; + $.setDesc = $defineProperty; + $.setDescs = $defineProperties; + $.getNames = $names.get = $getOwnPropertyNames; + $.getSymbols = $getOwnPropertySymbols; + + if(DESCRIPTORS && !__webpack_require__(40)){ + redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true); + } + } + + var symbolStatics = { + // 19.4.2.1 Symbol.for(key) + 'for': function(key){ + return has(SymbolRegistry, key += '') + ? SymbolRegistry[key] + : SymbolRegistry[key] = $Symbol(key); + }, + // 19.4.2.5 Symbol.keyFor(sym) + keyFor: function keyFor(key){ + return keyOf(SymbolRegistry, key); + }, + useSetter: function(){ setter = true; }, + useSimple: function(){ setter = false; } + }; + // 19.4.2.2 Symbol.hasInstance + // 19.4.2.3 Symbol.isConcatSpreadable + // 19.4.2.4 Symbol.iterator + // 19.4.2.6 Symbol.match + // 19.4.2.8 Symbol.replace + // 19.4.2.9 Symbol.search + // 19.4.2.10 Symbol.species + // 19.4.2.11 Symbol.split + // 19.4.2.12 Symbol.toPrimitive + // 19.4.2.13 Symbol.toStringTag + // 19.4.2.14 Symbol.unscopables + $.each.call(( + 'hasInstance,isConcatSpreadable,iterator,match,replace,search,' + + 'species,split,toPrimitive,toStringTag,unscopables' + ).split(','), function(it){ + var sym = wks(it); + symbolStatics[it] = useNative ? sym : wrap(sym); + }); + + setter = true; + + $export($export.G + $export.W, {Symbol: $Symbol}); + + $export($export.S, 'Symbol', symbolStatics); + + $export($export.S + $export.F * !useNative, 'Object', { + // 19.1.2.2 Object.create(O [, Properties]) + create: $create, + // 19.1.2.4 Object.defineProperty(O, P, Attributes) + defineProperty: $defineProperty, + // 19.1.2.3 Object.defineProperties(O, Properties) + defineProperties: $defineProperties, + // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) + getOwnPropertyDescriptor: $getOwnPropertyDescriptor, + // 19.1.2.7 Object.getOwnPropertyNames(O) + getOwnPropertyNames: $getOwnPropertyNames, + // 19.1.2.8 Object.getOwnPropertySymbols(O) + getOwnPropertySymbols: $getOwnPropertySymbols + }); + + // 24.3.2 JSON.stringify(value [, replacer [, space]]) + $JSON && $export($export.S + $export.F * (!useNative || buggyJSON), 'JSON', {stringify: $stringify}); + + // 19.4.3.5 Symbol.prototype[@@toStringTag] + setToStringTag($Symbol, 'Symbol'); + // 20.2.1.9 Math[@@toStringTag] + setToStringTag(Math, 'Math', true); + // 24.3.3 JSON[@@toStringTag] + setToStringTag(global.JSON, 'JSON', true); + +/***/ }), +/* 15 */ +/***/ (function(module, exports) { + + // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); + if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef + +/***/ }), +/* 16 */ +/***/ (function(module, exports) { + + var hasOwnProperty = {}.hasOwnProperty; + module.exports = function(it, key){ + return hasOwnProperty.call(it, key); + }; + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + + // Thank's IE8 for his funny defineProperty + module.exports = !__webpack_require__(18)(function(){ + return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7; + }); + +/***/ }), +/* 18 */ +/***/ (function(module, exports) { + + module.exports = function(exec){ + try { + return !!exec(); + } catch(e){ + return true; + } + }; + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + + var global = __webpack_require__(15) + , core = __webpack_require__(20) + , ctx = __webpack_require__(21) + , PROTOTYPE = 'prototype'; + + var $export = function(type, name, source){ + var IS_FORCED = type & $export.F + , IS_GLOBAL = type & $export.G + , IS_STATIC = type & $export.S + , IS_PROTO = type & $export.P + , IS_BIND = type & $export.B + , IS_WRAP = type & $export.W + , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) + , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] + , key, own, out; + if(IS_GLOBAL)source = name; + for(key in source){ + // contains in native + own = !IS_FORCED && target && key in target; + if(own && key in exports)continue; + // export native or passed + out = own ? target[key] : source[key]; + // prevent global pollution for namespaces + exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] + // bind timers to global for call from export context + : IS_BIND && own ? ctx(out, global) + // wrap global constructors for prevent change them in library + : IS_WRAP && target[key] == out ? (function(C){ + var F = function(param){ + return this instanceof C ? new C(param) : C(param); + }; + F[PROTOTYPE] = C[PROTOTYPE]; + return F; + // make static versions for prototype methods + })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; + if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; + } + }; + // type bitmap + $export.F = 1; // forced + $export.G = 2; // global + $export.S = 4; // static + $export.P = 8; // proto + $export.B = 16; // bind + $export.W = 32; // wrap + module.exports = $export; + +/***/ }), +/* 20 */ +/***/ (function(module, exports) { + + var core = module.exports = {version: '1.2.6'}; + if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + + // optional / simple context binding + var aFunction = __webpack_require__(22); + module.exports = function(fn, that, length){ + aFunction(fn); + if(that === undefined)return fn; + switch(length){ + case 1: return function(a){ + return fn.call(that, a); + }; + case 2: return function(a, b){ + return fn.call(that, a, b); + }; + case 3: return function(a, b, c){ + return fn.call(that, a, b, c); + }; + } + return function(/* ...args */){ + return fn.apply(that, arguments); + }; + }; + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + if(typeof it != 'function')throw TypeError(it + ' is not a function!'); + return it; + }; + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(24); + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(8) + , createDesc = __webpack_require__(25); + module.exports = __webpack_require__(17) ? function(object, key, value){ + return $.setDesc(object, key, createDesc(1, value)); + } : function(object, key, value){ + object[key] = value; + return object; + }; + +/***/ }), +/* 25 */ +/***/ (function(module, exports) { + + module.exports = function(bitmap, value){ + return { + enumerable : !(bitmap & 1), + configurable: !(bitmap & 2), + writable : !(bitmap & 4), + value : value + }; + }; + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + + var global = __webpack_require__(15) + , SHARED = '__core-js_shared__' + , store = global[SHARED] || (global[SHARED] = {}); + module.exports = function(key){ + return store[key] || (store[key] = {}); + }; + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + + var def = __webpack_require__(8).setDesc + , has = __webpack_require__(16) + , TAG = __webpack_require__(28)('toStringTag'); + + module.exports = function(it, tag, stat){ + if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag}); + }; + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + + var store = __webpack_require__(26)('wks') + , uid = __webpack_require__(29) + , Symbol = __webpack_require__(15).Symbol; + module.exports = function(name){ + return store[name] || (store[name] = + Symbol && Symbol[name] || (Symbol || uid)('Symbol.' + name)); + }; + +/***/ }), +/* 29 */ +/***/ (function(module, exports) { + + var id = 0 + , px = Math.random(); + module.exports = function(key){ + return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); + }; + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(8) + , toIObject = __webpack_require__(31); + module.exports = function(object, el){ + var O = toIObject(object) + , keys = $.getKeys(O) + , length = keys.length + , index = 0 + , key; + while(length > index)if(O[key = keys[index++]] === el)return key; + }; + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + + // to indexed object, toObject with fallback for non-array-like ES3 strings + var IObject = __webpack_require__(32) + , defined = __webpack_require__(34); + module.exports = function(it){ + return IObject(defined(it)); + }; + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + + // fallback for non-array-like ES3 and non-enumerable old V8 strings + var cof = __webpack_require__(33); + module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){ + return cof(it) == 'String' ? it.split('') : Object(it); + }; + +/***/ }), +/* 33 */ +/***/ (function(module, exports) { + + var toString = {}.toString; + + module.exports = function(it){ + return toString.call(it).slice(8, -1); + }; + +/***/ }), +/* 34 */ +/***/ (function(module, exports) { + + // 7.2.1 RequireObjectCoercible(argument) + module.exports = function(it){ + if(it == undefined)throw TypeError("Can't call method on " + it); + return it; + }; + +/***/ }), +/* 35 */ +/***/ (function(module, exports, __webpack_require__) { + + // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window + var toIObject = __webpack_require__(31) + , getNames = __webpack_require__(8).getNames + , toString = {}.toString; + + var windowNames = typeof window == 'object' && Object.getOwnPropertyNames + ? Object.getOwnPropertyNames(window) : []; + + var getWindowNames = function(it){ + try { + return getNames(it); + } catch(e){ + return windowNames.slice(); + } + }; + + module.exports.get = function getOwnPropertyNames(it){ + if(windowNames && toString.call(it) == '[object Window]')return getWindowNames(it); + return getNames(toIObject(it)); + }; + +/***/ }), +/* 36 */ +/***/ (function(module, exports, __webpack_require__) { + + // all enumerable object keys, includes symbols + var $ = __webpack_require__(8); + module.exports = function(it){ + var keys = $.getKeys(it) + , getSymbols = $.getSymbols; + if(getSymbols){ + var symbols = getSymbols(it) + , isEnum = $.isEnum + , i = 0 + , key; + while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))keys.push(key); + } + return keys; + }; + +/***/ }), +/* 37 */ +/***/ (function(module, exports, __webpack_require__) { + + // 7.2.2 IsArray(argument) + var cof = __webpack_require__(33); + module.exports = Array.isArray || function(arg){ + return cof(arg) == 'Array'; + }; + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + + var isObject = __webpack_require__(39); + module.exports = function(it){ + if(!isObject(it))throw TypeError(it + ' is not an object!'); + return it; + }; + +/***/ }), +/* 39 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + return typeof it === 'object' ? it !== null : typeof it === 'function'; + }; + +/***/ }), +/* 40 */ +/***/ (function(module, exports) { + + module.exports = true; + +/***/ }), +/* 41 */ +/***/ (function(module, exports) { + + + +/***/ }), +/* 42 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(43), __esModule: true }; + +/***/ }), +/* 43 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(44); + __webpack_require__(50); + module.exports = __webpack_require__(28)('iterator'); + +/***/ }), +/* 44 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var $at = __webpack_require__(45)(true); + + // 21.1.3.27 String.prototype[@@iterator]() + __webpack_require__(47)(String, 'String', function(iterated){ + this._t = String(iterated); // target + this._i = 0; // next index + // 21.1.5.2.1 %StringIteratorPrototype%.next() + }, function(){ + var O = this._t + , index = this._i + , point; + if(index >= O.length)return {value: undefined, done: true}; + point = $at(O, index); + this._i += point.length; + return {value: point, done: false}; + }); + +/***/ }), +/* 45 */ +/***/ (function(module, exports, __webpack_require__) { + + var toInteger = __webpack_require__(46) + , defined = __webpack_require__(34); + // true -> String#at + // false -> String#codePointAt + module.exports = function(TO_STRING){ + return function(that, pos){ + var s = String(defined(that)) + , i = toInteger(pos) + , l = s.length + , a, b; + if(i < 0 || i >= l)return TO_STRING ? '' : undefined; + a = s.charCodeAt(i); + return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff + ? TO_STRING ? s.charAt(i) : a + : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000; + }; + }; + +/***/ }), +/* 46 */ +/***/ (function(module, exports) { + + // 7.1.4 ToInteger + var ceil = Math.ceil + , floor = Math.floor; + module.exports = function(it){ + return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); + }; + +/***/ }), +/* 47 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var LIBRARY = __webpack_require__(40) + , $export = __webpack_require__(19) + , redefine = __webpack_require__(23) + , hide = __webpack_require__(24) + , has = __webpack_require__(16) + , Iterators = __webpack_require__(48) + , $iterCreate = __webpack_require__(49) + , setToStringTag = __webpack_require__(27) + , getProto = __webpack_require__(8).getProto + , ITERATOR = __webpack_require__(28)('iterator') + , BUGGY = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next` + , FF_ITERATOR = '@@iterator' + , KEYS = 'keys' + , VALUES = 'values'; + + var returnThis = function(){ return this; }; + + module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){ + $iterCreate(Constructor, NAME, next); + var getMethod = function(kind){ + if(!BUGGY && kind in proto)return proto[kind]; + switch(kind){ + case KEYS: return function keys(){ return new Constructor(this, kind); }; + case VALUES: return function values(){ return new Constructor(this, kind); }; + } return function entries(){ return new Constructor(this, kind); }; + }; + var TAG = NAME + ' Iterator' + , DEF_VALUES = DEFAULT == VALUES + , VALUES_BUG = false + , proto = Base.prototype + , $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT] + , $default = $native || getMethod(DEFAULT) + , methods, key; + // Fix native + if($native){ + var IteratorPrototype = getProto($default.call(new Base)); + // Set @@toStringTag to native iterators + setToStringTag(IteratorPrototype, TAG, true); + // FF fix + if(!LIBRARY && has(proto, FF_ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis); + // fix Array#{values, @@iterator}.name in V8 / FF + if(DEF_VALUES && $native.name !== VALUES){ + VALUES_BUG = true; + $default = function values(){ return $native.call(this); }; + } + } + // Define iterator + if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){ + hide(proto, ITERATOR, $default); + } + // Plug for library + Iterators[NAME] = $default; + Iterators[TAG] = returnThis; + if(DEFAULT){ + methods = { + values: DEF_VALUES ? $default : getMethod(VALUES), + keys: IS_SET ? $default : getMethod(KEYS), + entries: !DEF_VALUES ? $default : getMethod('entries') + }; + if(FORCED)for(key in methods){ + if(!(key in proto))redefine(proto, key, methods[key]); + } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); + } + return methods; + }; + +/***/ }), +/* 48 */ +/***/ (function(module, exports) { + + module.exports = {}; + +/***/ }), +/* 49 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var $ = __webpack_require__(8) + , descriptor = __webpack_require__(25) + , setToStringTag = __webpack_require__(27) + , IteratorPrototype = {}; + + // 25.1.2.1.1 %IteratorPrototype%[@@iterator]() + __webpack_require__(24)(IteratorPrototype, __webpack_require__(28)('iterator'), function(){ return this; }); + + module.exports = function(Constructor, NAME, next){ + Constructor.prototype = $.create(IteratorPrototype, {next: descriptor(1, next)}); + setToStringTag(Constructor, NAME + ' Iterator'); + }; + +/***/ }), +/* 50 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(51); + var Iterators = __webpack_require__(48); + Iterators.NodeList = Iterators.HTMLCollection = Iterators.Array; + +/***/ }), +/* 51 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var addToUnscopables = __webpack_require__(52) + , step = __webpack_require__(53) + , Iterators = __webpack_require__(48) + , toIObject = __webpack_require__(31); + + // 22.1.3.4 Array.prototype.entries() + // 22.1.3.13 Array.prototype.keys() + // 22.1.3.29 Array.prototype.values() + // 22.1.3.30 Array.prototype[@@iterator]() + module.exports = __webpack_require__(47)(Array, 'Array', function(iterated, kind){ + this._t = toIObject(iterated); // target + this._i = 0; // next index + this._k = kind; // kind + // 22.1.5.2.1 %ArrayIteratorPrototype%.next() + }, function(){ + var O = this._t + , kind = this._k + , index = this._i++; + if(!O || index >= O.length){ + this._t = undefined; + return step(1); + } + if(kind == 'keys' )return step(0, index); + if(kind == 'values')return step(0, O[index]); + return step(0, [index, O[index]]); + }, 'values'); + + // argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7) + Iterators.Arguments = Iterators.Array; + + addToUnscopables('keys'); + addToUnscopables('values'); + addToUnscopables('entries'); + +/***/ }), +/* 52 */ +/***/ (function(module, exports) { + + module.exports = function(){ /* empty */ }; + +/***/ }), +/* 53 */ +/***/ (function(module, exports) { + + module.exports = function(done, value){ + return {value: value, done: !!done}; + }; + +/***/ }), +/* 54 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(55), __esModule: true }; + +/***/ }), +/* 55 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(50); + __webpack_require__(44); + module.exports = __webpack_require__(56); + +/***/ }), +/* 56 */ +/***/ (function(module, exports, __webpack_require__) { + + var anObject = __webpack_require__(38) + , get = __webpack_require__(57); + module.exports = __webpack_require__(20).getIterator = function(it){ + var iterFn = get(it); + if(typeof iterFn != 'function')throw TypeError(it + ' is not iterable!'); + return anObject(iterFn.call(it)); + }; + +/***/ }), +/* 57 */ +/***/ (function(module, exports, __webpack_require__) { + + var classof = __webpack_require__(58) + , ITERATOR = __webpack_require__(28)('iterator') + , Iterators = __webpack_require__(48); + module.exports = __webpack_require__(20).getIteratorMethod = function(it){ + if(it != undefined)return it[ITERATOR] + || it['@@iterator'] + || Iterators[classof(it)]; + }; + +/***/ }), +/* 58 */ +/***/ (function(module, exports, __webpack_require__) { + + // getting tag from 19.1.3.6 Object.prototype.toString() + var cof = __webpack_require__(33) + , TAG = __webpack_require__(28)('toStringTag') + // ES3 wrong here + , ARG = cof(function(){ return arguments; }()) == 'Arguments'; + + module.exports = function(it){ + var O, T, B; + return it === undefined ? 'Undefined' : it === null ? 'Null' + // @@toStringTag case + : typeof (T = (O = Object(it))[TAG]) == 'string' ? T + // builtinTag case + : ARG ? cof(O) + // ES3 arguments fallback + : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; + }; + +/***/ }), +/* 59 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(60), __esModule: true }; + +/***/ }), +/* 60 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(61); + module.exports = __webpack_require__(20).Object.keys; + +/***/ }), +/* 61 */ +/***/ (function(module, exports, __webpack_require__) { + + // 19.1.2.14 Object.keys(O) + var toObject = __webpack_require__(62); + + __webpack_require__(63)('keys', function($keys){ + return function keys(it){ + return $keys(toObject(it)); + }; + }); + +/***/ }), +/* 62 */ +/***/ (function(module, exports, __webpack_require__) { + + // 7.1.13 ToObject(argument) + var defined = __webpack_require__(34); + module.exports = function(it){ + return Object(defined(it)); + }; + +/***/ }), +/* 63 */ +/***/ (function(module, exports, __webpack_require__) { + + // most Object methods by ES6 should accept primitives + var $export = __webpack_require__(19) + , core = __webpack_require__(20) + , fails = __webpack_require__(18); + module.exports = function(KEY, exec){ + var fn = (core.Object || {})[KEY] || Object[KEY] + , exp = {}; + exp[KEY] = exec(fn); + $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); + }; + +/***/ }), +/* 64 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + + var _exception = __webpack_require__(5); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('helperMissing', function () /* [args, ]options */{ + if (arguments.length === 1) { + // A missing field in a {{foo}} construct. + return undefined; + } else { + // Someone is actually trying to call something, blow up. + throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"'); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 65 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(4); + + var _exception = __webpack_require__(5); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('if', function (conditional, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#if requires exactly one argument'); + } + if (_utils.isFunction(conditional)) { + conditional = conditional.call(this); + } + + // Default behavior is to render the positive path if the value is truthy and not empty. + // The `includeZero` option may be set to treat the condtional as purely not empty based on the + // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. + if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) { + return options.inverse(this); + } else { + return options.fn(this); + } + }); + + instance.registerHelper('unless', function (conditional, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#unless requires exactly one argument'); + } + return instance.helpers['if'].call(this, conditional, { + fn: options.inverse, + inverse: options.fn, + hash: options.hash + }); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 66 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('log', function () /* message, options */{ + var args = [undefined], + options = arguments[arguments.length - 1]; + for (var i = 0; i < arguments.length - 1; i++) { + args.push(arguments[i]); + } + + var level = 1; + if (options.hash.level != null) { + level = options.hash.level; + } else if (options.data && options.data.level != null) { + level = options.data.level; + } + args[0] = level; + + instance.log.apply(instance, args); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 67 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('lookup', function (obj, field, options) { + if (!obj) { + // Note for 5.0: Change to "obj == null" in 5.0 + return obj; + } + return options.lookupProperty(obj, field); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 68 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(4); + + var _exception = __webpack_require__(5); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('with', function (context, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#with requires exactly one argument'); + } + if (_utils.isFunction(context)) { + context = context.call(this); + } + + var fn = options.fn; + + if (!_utils.isEmpty(context)) { + var data = options.data; + if (options.data && options.ids) { + data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]); + } + + return fn(context, { + data: data, + blockParams: _utils.blockParams([context], [data && data.contextPath]) + }); + } else { + return options.inverse(this); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 69 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + exports.registerDefaultDecorators = registerDefaultDecorators; + + var _decoratorsInline = __webpack_require__(70); + + var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline); + + function registerDefaultDecorators(instance) { + _decoratorsInline2['default'](instance); + } + +/***/ }), +/* 70 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(4); + + exports['default'] = function (instance) { + instance.registerDecorator('inline', function (fn, props, container, options) { + var ret = fn; + if (!props.partials) { + props.partials = {}; + ret = function (context, options) { + // Create a new partials stack frame prior to exec. + var original = container.partials; + container.partials = _utils.extend({}, original, props.partials); + var ret = fn(context, options); + container.partials = original; + return ret; + }; + } + + props.partials[options.args[0]] = options.fn; + + return ret; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 71 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(4); + + var logger = { + methodMap: ['debug', 'info', 'warn', 'error'], + level: 'info', + + // Maps a given level value to the `methodMap` indexes above. + lookupLevel: function lookupLevel(level) { + if (typeof level === 'string') { + var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase()); + if (levelMap >= 0) { + level = levelMap; + } else { + level = parseInt(level, 10); + } + } + + return level; + }, + + // Can be overridden in the host environment + log: function log(level) { + level = logger.lookupLevel(level); + + if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) { + var method = logger.methodMap[level]; + // eslint-disable-next-line no-console + if (!console[method]) { + method = 'log'; + } + + for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + message[_key - 1] = arguments[_key]; + } + + console[method].apply(console, message); // eslint-disable-line no-console + } + } + }; + + exports['default'] = logger; + module.exports = exports['default']; + +/***/ }), +/* 72 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$create = __webpack_require__(73)['default']; + + var _Object$keys = __webpack_require__(59)['default']; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + exports.createProtoAccessControl = createProtoAccessControl; + exports.resultIsAllowed = resultIsAllowed; + exports.resetLoggedProperties = resetLoggedProperties; + + var _createNewLookupObject = __webpack_require__(75); + + var _logger = __webpack_require__(71); + + var _logger2 = _interopRequireDefault(_logger); + + var loggedProperties = _Object$create(null); + + function createProtoAccessControl(runtimeOptions) { + var defaultMethodWhiteList = _Object$create(null); + defaultMethodWhiteList['constructor'] = false; + defaultMethodWhiteList['__defineGetter__'] = false; + defaultMethodWhiteList['__defineSetter__'] = false; + defaultMethodWhiteList['__lookupGetter__'] = false; + + var defaultPropertyWhiteList = _Object$create(null); + // eslint-disable-next-line no-proto + defaultPropertyWhiteList['__proto__'] = false; + + return { + properties: { + whitelist: _createNewLookupObject.createNewLookupObject(defaultPropertyWhiteList, runtimeOptions.allowedProtoProperties), + defaultValue: runtimeOptions.allowProtoPropertiesByDefault + }, + methods: { + whitelist: _createNewLookupObject.createNewLookupObject(defaultMethodWhiteList, runtimeOptions.allowedProtoMethods), + defaultValue: runtimeOptions.allowProtoMethodsByDefault + } + }; + } + + function resultIsAllowed(result, protoAccessControl, propertyName) { + if (typeof result === 'function') { + return checkWhiteList(protoAccessControl.methods, propertyName); + } else { + return checkWhiteList(protoAccessControl.properties, propertyName); + } + } + + function checkWhiteList(protoAccessControlForType, propertyName) { + if (protoAccessControlForType.whitelist[propertyName] !== undefined) { + return protoAccessControlForType.whitelist[propertyName] === true; + } + if (protoAccessControlForType.defaultValue !== undefined) { + return protoAccessControlForType.defaultValue; + } + logUnexpecedPropertyAccessOnce(propertyName); + return false; + } + + function logUnexpecedPropertyAccessOnce(propertyName) { + if (loggedProperties[propertyName] !== true) { + loggedProperties[propertyName] = true; + _logger2['default'].log('error', 'Handlebars: Access has been denied to resolve the property "' + propertyName + '" because it is not an "own property" of its parent.\n' + 'You can add a runtime option to disable the check or this warning:\n' + 'See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details'); + } + } + + function resetLoggedProperties() { + _Object$keys(loggedProperties).forEach(function (propertyName) { + delete loggedProperties[propertyName]; + }); + } + +/***/ }), +/* 73 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(74), __esModule: true }; + +/***/ }), +/* 74 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(8); + module.exports = function create(P, D){ + return $.create(P, D); + }; + +/***/ }), +/* 75 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$create = __webpack_require__(73)['default']; + + exports.__esModule = true; + exports.createNewLookupObject = createNewLookupObject; + + var _utils = __webpack_require__(4); + + /** + * Create a new object with "null"-prototype to avoid truthy results on prototype properties. + * The resulting object can be used with "object[property]" to check if a property exists + * @param {...object} sources a varargs parameter of source objects that will be merged + * @returns {object} + */ + + function createNewLookupObject() { + for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) { + sources[_key] = arguments[_key]; + } + + return _utils.extend.apply(undefined, [_Object$create(null)].concat(sources)); + } + +/***/ }), +/* 76 */ +/***/ (function(module, exports) { + + // Build out our basic SafeString type + 'use strict'; + + exports.__esModule = true; + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = SafeString.prototype.toHTML = function () { + return '' + this.string; + }; + + exports['default'] = SafeString; + module.exports = exports['default']; + +/***/ }), +/* 77 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$seal = __webpack_require__(78)['default']; + + var _Object$keys = __webpack_require__(59)['default']; + + var _interopRequireWildcard = __webpack_require__(1)['default']; + + var _interopRequireDefault = __webpack_require__(2)['default']; + + exports.__esModule = true; + exports.checkRevision = checkRevision; + exports.template = template; + exports.wrapProgram = wrapProgram; + exports.resolvePartial = resolvePartial; + exports.invokePartial = invokePartial; + exports.noop = noop; + + var _utils = __webpack_require__(4); + + var Utils = _interopRequireWildcard(_utils); + + var _exception = __webpack_require__(5); + + var _exception2 = _interopRequireDefault(_exception); + + var _base = __webpack_require__(3); + + var _helpers = __webpack_require__(9); + + var _internalWrapHelper = __webpack_require__(81); + + var _internalProtoAccess = __webpack_require__(72); + + function checkRevision(compilerInfo) { + var compilerRevision = compilerInfo && compilerInfo[0] || 1, + currentRevision = _base.COMPILER_REVISION; + + if (compilerRevision >= _base.LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= _base.COMPILER_REVISION) { + return; + } + + if (compilerRevision < _base.LAST_COMPATIBLE_COMPILER_REVISION) { + var runtimeVersions = _base.REVISION_CHANGES[currentRevision], + compilerVersions = _base.REVISION_CHANGES[compilerRevision]; + throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); + } + } + + function template(templateSpec, env) { + /* istanbul ignore next */ + if (!env) { + throw new _exception2['default']('No environment passed to template'); + } + if (!templateSpec || !templateSpec.main) { + throw new _exception2['default']('Unknown template object: ' + typeof templateSpec); + } + + templateSpec.main.decorator = templateSpec.main_d; + + // Note: Using env.VM references rather than local var references throughout this section to allow + // for external users to override these as pseudo-supported APIs. + env.VM.checkRevision(templateSpec.compiler); + + // backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0) + var templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7; + + function invokePartialWrapper(partial, context, options) { + if (options.hash) { + context = Utils.extend({}, context, options.hash); + if (options.ids) { + options.ids[0] = true; + } + } + partial = env.VM.resolvePartial.call(this, partial, context, options); + + var extendedOptions = Utils.extend({}, options, { + hooks: this.hooks, + protoAccessControl: this.protoAccessControl + }); + + var result = env.VM.invokePartial.call(this, partial, context, extendedOptions); + + if (result == null && env.compile) { + options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); + result = options.partials[options.name](context, extendedOptions); + } + if (result != null) { + if (options.indent) { + var lines = result.split('\n'); + for (var i = 0, l = lines.length; i < l; i++) { + if (!lines[i] && i + 1 === l) { + break; + } + + lines[i] = options.indent + lines[i]; + } + result = lines.join('\n'); + } + return result; + } else { + throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); + } + } + + // Just add water + var container = { + strict: function strict(obj, name, loc) { + if (!obj || !(name in obj)) { + throw new _exception2['default']('"' + name + '" not defined in ' + obj, { + loc: loc + }); + } + return container.lookupProperty(obj, name); + }, + lookupProperty: function lookupProperty(parent, propertyName) { + var result = parent[propertyName]; + if (result == null) { + return result; + } + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return result; + } + + if (_internalProtoAccess.resultIsAllowed(result, container.protoAccessControl, propertyName)) { + return result; + } + return undefined; + }, + lookup: function lookup(depths, name) { + var len = depths.length; + for (var i = 0; i < len; i++) { + var result = depths[i] && container.lookupProperty(depths[i], name); + if (result != null) { + return depths[i][name]; + } + } + }, + lambda: function lambda(current, context) { + return typeof current === 'function' ? current.call(context) : current; + }, + + escapeExpression: Utils.escapeExpression, + invokePartial: invokePartialWrapper, + + fn: function fn(i) { + var ret = templateSpec[i]; + ret.decorator = templateSpec[i + '_d']; + return ret; + }, + + programs: [], + program: function program(i, data, declaredBlockParams, blockParams, depths) { + var programWrapper = this.programs[i], + fn = this.fn(i); + if (data || depths || blockParams || declaredBlockParams) { + programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); + } else if (!programWrapper) { + programWrapper = this.programs[i] = wrapProgram(this, i, fn); + } + return programWrapper; + }, + + data: function data(value, depth) { + while (value && depth--) { + value = value._parent; + } + return value; + }, + mergeIfNeeded: function mergeIfNeeded(param, common) { + var obj = param || common; + + if (param && common && param !== common) { + obj = Utils.extend({}, common, param); + } + + return obj; + }, + // An empty object to use as replacement for null-contexts + nullContext: _Object$seal({}), + + noop: env.VM.noop, + compilerInfo: templateSpec.compiler + }; + + function ret(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var data = options.data; + + ret._setup(options); + if (!options.partial && templateSpec.useData) { + data = initData(context, data); + } + var depths = undefined, + blockParams = templateSpec.useBlockParams ? [] : undefined; + if (templateSpec.useDepths) { + if (options.depths) { + depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; + } else { + depths = [context]; + } + } + + function main(context /*, options*/) { + return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths); + } + + main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams); + return main(context, options); + } + + ret.isTop = true; + + ret._setup = function (options) { + if (!options.partial) { + var mergedHelpers = Utils.extend({}, env.helpers, options.helpers); + wrapHelpersToPassLookupProperty(mergedHelpers, container); + container.helpers = mergedHelpers; + + if (templateSpec.usePartial) { + // Use mergeIfNeeded here to prevent compiling global partials multiple times + container.partials = container.mergeIfNeeded(options.partials, env.partials); + } + if (templateSpec.usePartial || templateSpec.useDecorators) { + container.decorators = Utils.extend({}, env.decorators, options.decorators); + } + + container.hooks = {}; + container.protoAccessControl = _internalProtoAccess.createProtoAccessControl(options); + + var keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7; + _helpers.moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers); + _helpers.moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers); + } else { + container.protoAccessControl = options.protoAccessControl; // internal option + container.helpers = options.helpers; + container.partials = options.partials; + container.decorators = options.decorators; + container.hooks = options.hooks; + } + }; + + ret._child = function (i, data, blockParams, depths) { + if (templateSpec.useBlockParams && !blockParams) { + throw new _exception2['default']('must pass block params'); + } + if (templateSpec.useDepths && !depths) { + throw new _exception2['default']('must pass parent depths'); + } + + return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); + }; + return ret; + } + + function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { + function prog(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var currentDepths = depths; + if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) { + currentDepths = [context].concat(depths); + } + + return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths); + } + + prog = executeDecorators(fn, prog, container, depths, data, blockParams); + + prog.program = i; + prog.depth = depths ? depths.length : 0; + prog.blockParams = declaredBlockParams || 0; + return prog; + } + + /** + * This is currently part of the official API, therefore implementation details should not be changed. + */ + + function resolvePartial(partial, context, options) { + if (!partial) { + if (options.name === '@partial-block') { + partial = options.data['partial-block']; + } else { + partial = options.partials[options.name]; + } + } else if (!partial.call && !options.name) { + // This is a dynamic partial that returned a string + options.name = partial; + partial = options.partials[partial]; + } + return partial; + } + + function invokePartial(partial, context, options) { + // Use the current closure context to save the partial-block if this partial + var currentPartialBlock = options.data && options.data['partial-block']; + options.partial = true; + if (options.ids) { + options.data.contextPath = options.ids[0] || options.data.contextPath; + } + + var partialBlock = undefined; + if (options.fn && options.fn !== noop) { + (function () { + options.data = _base.createFrame(options.data); + // Wrapper function to get access to currentPartialBlock from the closure + var fn = options.fn; + partialBlock = options.data['partial-block'] = function partialBlockWrapper(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + // Restore the partial-block from the closure for the execution of the block + // i.e. the part inside the block of the partial call. + options.data = _base.createFrame(options.data); + options.data['partial-block'] = currentPartialBlock; + return fn(context, options); + }; + if (fn.partials) { + options.partials = Utils.extend({}, options.partials, fn.partials); + } + })(); + } + + if (partial === undefined && partialBlock) { + partial = partialBlock; + } + + if (partial === undefined) { + throw new _exception2['default']('The partial ' + options.name + ' could not be found'); + } else if (partial instanceof Function) { + return partial(context, options); + } + } + + function noop() { + return ''; + } + + function initData(context, data) { + if (!data || !('root' in data)) { + data = data ? _base.createFrame(data) : {}; + data.root = context; + } + return data; + } + + function executeDecorators(fn, prog, container, depths, data, blockParams) { + if (fn.decorator) { + var props = {}; + prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths); + Utils.extend(prog, props); + } + return prog; + } + + function wrapHelpersToPassLookupProperty(mergedHelpers, container) { + _Object$keys(mergedHelpers).forEach(function (helperName) { + var helper = mergedHelpers[helperName]; + mergedHelpers[helperName] = passLookupPropertyOption(helper, container); + }); + } + + function passLookupPropertyOption(helper, container) { + var lookupProperty = container.lookupProperty; + return _internalWrapHelper.wrapHelper(helper, function (options) { + return Utils.extend({ lookupProperty: lookupProperty }, options); + }); + } + +/***/ }), +/* 78 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(79), __esModule: true }; + +/***/ }), +/* 79 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(80); + module.exports = __webpack_require__(20).Object.seal; + +/***/ }), +/* 80 */ +/***/ (function(module, exports, __webpack_require__) { + + // 19.1.2.17 Object.seal(O) + var isObject = __webpack_require__(39); + + __webpack_require__(63)('seal', function($seal){ + return function seal(it){ + return $seal && isObject(it) ? $seal(it) : it; + }; + }); + +/***/ }), +/* 81 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports.wrapHelper = wrapHelper; + + function wrapHelper(helper, transformOptionsFn) { + if (typeof helper !== 'function') { + // This should not happen, but apparently it does in https://github.com/wycats/handlebars.js/issues/1639 + // We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function. + return helper; + } + var wrapper = function wrapper() /* dynamic arguments */{ + var options = arguments[arguments.length - 1]; + arguments[arguments.length - 1] = transformOptionsFn(options); + return helper.apply(this, arguments); + }; + return wrapper; + } + +/***/ }), +/* 82 */ +/***/ (function(module, exports) { + + /* global globalThis */ + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (Handlebars) { + /* istanbul ignore next */ + // https://mathiasbynens.be/notes/globalthis + (function () { + if (typeof globalThis === 'object') return; + Object.prototype.__defineGetter__('__magic__', function () { + return this; + }); + __magic__.globalThis = __magic__; // eslint-disable-line no-undef + delete Object.prototype.__magic__; + })(); + + var $Handlebars = globalThis.Handlebars; + + /* istanbul ignore next */ + Handlebars.noConflict = function () { + if (globalThis.Handlebars === Handlebars) { + globalThis.Handlebars = $Handlebars; + } + return Handlebars; + }; + }; + + module.exports = exports['default']; + +/***/ }) +/******/ ]) +}); +; diff --git a/orochi/static/js/handlebars/plugins.js b/orochi/static/js/handlebars/plugins.js new file mode 100644 index 00000000..1ef4dfa6 --- /dev/null +++ b/orochi/static/js/handlebars/plugins.js @@ -0,0 +1,28 @@ +(function() { + var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; +templates['plugins'] = template({"1":function(container,depth0,helpers,partials,data) { + var alias1=container.lambda, alias2=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
  • \n \n
  • \n"; +},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),depth0,{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":9}}})) != null ? stack1 : ""); +},"useData":true}); +})(); diff --git a/orochi/templates/base.html b/orochi/templates/base.html index 04c4c3d4..1185639c 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -157,6 +157,9 @@ {% endblock modal %} {% block javascript %} + + \n"; +},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
    \n
    Maxmind Report
    \n \n
    \n
    \n" + + ((stack1 = lookupProperty(helpers,"if").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"errors") : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.program(3, data, 0),"data":data,"loc":{"start":{"line":6,"column":4},"end":{"line":24,"column":11}}})) != null ? stack1 : "") + + "
    \n
    \n \n
    \n\n"; +},"useData":true}); +})(); diff --git a/orochi/static/js/handlebars/vt.js b/orochi/static/js/handlebars/vt.js new file mode 100644 index 00000000..f5cea5a1 --- /dev/null +++ b/orochi/static/js/handlebars/vt.js @@ -0,0 +1,37 @@ +(function() { + var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; +templates['vt'] = template({"1":function(container,depth0,helpers,partials,data) { + var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
    \n " + + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"errors") || (depth0 != null ? lookupProperty(depth0,"errors") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"errors","hash":{},"data":data,"loc":{"start":{"line":8,"column":4},"end":{"line":8,"column":14}}}) : helper))) + + "\n
    \n"; +},"3":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
    \n \n"; +},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
    \n
    VirusTotal Report
    \n \n
    \n
    \n" + + ((stack1 = lookupProperty(helpers,"if").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"errors") : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.program(3, data, 0),"data":data,"loc":{"start":{"line":6,"column":4},"end":{"line":24,"column":11}}})) != null ? stack1 : "") + + "
    \n
    \n \n
    \n\n"; +},"useData":true}); +})(); diff --git a/orochi/templates/base.html b/orochi/templates/base.html index 1185639c..b670c7c6 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -20,6 +20,7 @@ + {% endblock %} @@ -160,6 +161,8 @@ + + + + {{/if}} + + + diff --git a/orochi/templates/handlebars/vt.handlebars b/orochi/templates/handlebars/vt.handlebars new file mode 100644 index 00000000..94f99011 --- /dev/null +++ b/orochi/templates/handlebars/vt.handlebars @@ -0,0 +1,29 @@ + + + + diff --git a/orochi/templates/users/user_bookmarks.html b/orochi/templates/users/user_bookmarks.html index b27ce47d..2d156827 100644 --- a/orochi/templates/users/user_bookmarks.html +++ b/orochi/templates/users/user_bookmarks.html @@ -91,6 +91,7 @@ type: 'get', dataType: 'json', beforeSend: function () { + $("#modal-update .modal-content").html(''); $("#modal-update").modal("show"); row = table.row($(btn).closest('tr')).index(); }, @@ -210,4 +211,4 @@ }); -{% endblock javascript %} \ No newline at end of file +{% endblock javascript %} diff --git a/orochi/templates/users/user_rules.html b/orochi/templates/users/user_rules.html index 4fa41b51..a0cdb6d7 100644 --- a/orochi/templates/users/user_rules.html +++ b/orochi/templates/users/user_rules.html @@ -260,6 +260,7 @@ dataType: 'json', beforeSend: function () { $("#modal-update .modal-dialog").removeClass('modal-xl'); + $("#modal-update .modal-content").html(''); $("#modal-update").modal("show"); }, success: function (data) { @@ -310,6 +311,7 @@ dataType: 'json', success: function (data) { $("#modal-update .modal-dialog").addClass('modal-xl'); + $("#modal-update .modal-content").html(''); $("#modal-update").modal("show"); $("#modal-update .modal-content").html(data.html_form); }, @@ -386,4 +388,4 @@ }); -{% endblock javascript %} \ No newline at end of file +{% endblock javascript %} diff --git a/orochi/templates/website/file_download.html b/orochi/templates/website/file_download.html index 9d7292eb..4b3b8750 100644 --- a/orochi/templates/website/file_download.html +++ b/orochi/templates/website/file_download.html @@ -15,7 +15,7 @@
    {% endif %} {% if vt %} - + {% endif %} diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index 2757a036..ba3ed74c 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -72,6 +72,12 @@
    History Log
    \n"; },"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { diff --git a/orochi/static/js/handlebars/vt.js b/orochi/static/js/handlebars/vt.js index f5cea5a1..9c02face 100644 --- a/orochi/static/js/handlebars/vt.js +++ b/orochi/static/js/handlebars/vt.js @@ -20,7 +20,7 @@ templates['vt'] = template({"1":function(container,depth0,helpers,partials,data) }; return "
    \n \n"; },"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { diff --git a/orochi/templates/handlebars/maxmind.handlebars b/orochi/templates/handlebars/maxmind.handlebars index 19120be6..c6a988d5 100644 --- a/orochi/templates/handlebars/maxmind.handlebars +++ b/orochi/templates/handlebars/maxmind.handlebars @@ -19,7 +19,7 @@ } var json_viewer = document.getElementById("js_received") var json_container = new JSONEditor(json_viewer, options) - json_container.set({{{ json info }}}) + json_container.set({{{ json . }}}) {{/if}} diff --git a/orochi/templates/handlebars/vt.handlebars b/orochi/templates/handlebars/vt.handlebars index 94f99011..ca7b3726 100644 --- a/orochi/templates/handlebars/vt.handlebars +++ b/orochi/templates/handlebars/vt.handlebars @@ -19,7 +19,7 @@ } var json_viewer = document.getElementById("js_received") var json_container = new JSONEditor(json_viewer, options) - json_container.set({{{ json info }}}) + json_container.set({{{ json . }}}) {{/if}} diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index ba3ed74c..a903359c 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -199,6 +199,7 @@
    History Log
    method: 'get', beforeSend: function () { $("#modal-update .modal-content").html(''); + $("#modal-update").addClass("modal-xl"); $("#modal-update").modal("show"); }, success: function (data) { @@ -222,6 +223,7 @@
    History Log
    method: 'get', beforeSend: function () { $("#modal-update .modal-content").html(''); + $("#modal-update").addClass("modal-xl"); $("#modal-update").modal("show"); }, success: function (data) { From f4296b2573d58c16224dc43d4236c992cbcc7af3 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 16 Apr 2024 17:31:37 +0200 Subject: [PATCH 51/84] #1073 wip --- orochi/api/api.py | 2 + orochi/api/models.py | 14 +- orochi/api/routers/bookmarks.py | 83 ++++++++++++ orochi/api/routers/plugins.py | 2 +- orochi/api/routers/utils.py | 7 + orochi/static/css/style.css | 9 ++ orochi/templates/base.html | 4 +- orochi/templates/users/user_bookmarks.html | 28 ++-- orochi/templates/users/user_plugins.html | 2 +- orochi/templates/website/index.html | 1 - orochi/templates/website/partial_indices.html | 2 +- orochi/users/views.py | 16 +-- orochi/website/urls.py | 2 - orochi/website/views.py | 125 +++++++----------- 14 files changed, 191 insertions(+), 106 deletions(-) create mode 100644 orochi/api/routers/bookmarks.py diff --git a/orochi/api/api.py b/orochi/api/api.py index c64dd814..8dea779d 100644 --- a/orochi/api/api.py +++ b/orochi/api/api.py @@ -1,6 +1,7 @@ from ninja import NinjaAPI from orochi.api.routers.auth import router as auth_router +from orochi.api.routers.bookmarks import router as bookmarks_router from orochi.api.routers.dumps import router as dumps_router from orochi.api.routers.folders import router as folders_router from orochi.api.routers.plugins import router as plugins_router @@ -14,3 +15,4 @@ api.add_router("/dumps/", dumps_router, tags=["Dumps"]) api.add_router("/plugins/", plugins_router, tags=["Plugins"]) api.add_router("/utils/", utils_router, tags=["Utils"]) +api.add_router("/bookmars/", bookmarks_router, tags=["Bookmars"]) diff --git a/orochi/api/models.py b/orochi/api/models.py index 433206a8..ad766799 100644 --- a/orochi/api/models.py +++ b/orochi/api/models.py @@ -6,7 +6,7 @@ from ninja.orm import create_schema from orochi.website.defaults import OSEnum -from orochi.website.models import Dump, Folder, Plugin, Result +from orochi.website.models import Bookmark, Dump, Folder, Plugin, Result ################################################### # Auth @@ -205,3 +205,15 @@ class Meta: class ResultSmallOutSchema(Schema): name: str = Field(..., alias="plugin__name") comment: str = Field(..., alias="plugin__comment") + + +################################################### +# Bookmarks +################################################### +class BookmarksSchema(ModelSchema): + user: UserOutSchema = None + indexes: List[DumpSchema] = [] + + class Meta: + model = Bookmark + fields = ["id", "name", "icon", "star", "query"] diff --git a/orochi/api/routers/bookmarks.py b/orochi/api/routers/bookmarks.py new file mode 100644 index 00000000..dbf0f0c3 --- /dev/null +++ b/orochi/api/routers/bookmarks.py @@ -0,0 +1,83 @@ +from typing import List + +from django.shortcuts import get_object_or_404 +from ninja import Router +from ninja.security import django_auth + +from orochi.api.models import BookmarksSchema, ErrorsOut, SuccessResponse +from orochi.website.models import Bookmark + +router = Router() + + +@router.get("/", auth=django_auth, response=List[BookmarksSchema]) +def list_bookmarks(request): + """ + Retrieves a list of bookmarks for the current user. + + Returns: + QuerySet: A queryset of bookmarks belonging to the current user. + """ + return Bookmark.objects.filter(user=request.user) + + +@router.delete( + "/{int:id}", + auth=django_auth, + url_name="delete_bookmark", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def delete_bookmarks(request, id: int): + """ + Deletes a bookmark by its ID. + + Args: + id (int): The ID of the bookmark to delete. + + Returns: + tuple: A tuple containing the status code and a message dictionary. + + Raises: + Exception: If an error occurs during the deletion process. + """ + bookmark = get_object_or_404(Bookmark, pk=id, user=request.user) + name = bookmark.name + try: + bookmark.delete() + return 200, {"message": f"Bookmark {name} deleted"} + except Exception as excp: + return 400, {"errors": str(excp)} + + +@router.post( + "/{int:id}/star/{star}", + auth=django_auth, + url_name="star_bookmark", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def star_bookmark(request, id: int, star: bool): + """ + Stars or unstars a bookmark. + + Args: + id (int): The ID of the bookmark to star/unstar. + star (bool): True to star the bookmark, False to unstar it. + + Returns: + tuple: A tuple containing the HTTP status code and a message dict. + + Raises: + Exception: If an error occurs during the process. + """ + try: + bookmark = get_object_or_404(Bookmark, pk=id, user=request.user) + name = bookmark.name + bookmark.star = star + bookmark.save() + return 200, { + "message": ( + f"Bookmark {name} starred" if star else f"Bookmark {name} unstarred" + ) + } + except Exception as excp: + return 400, {"errors": str(excp)} diff --git a/orochi/api/routers/plugins.py b/orochi/api/routers/plugins.py index 5b443633..72b843da 100644 --- a/orochi/api/routers/plugins.py +++ b/orochi/api/routers/plugins.py @@ -156,7 +156,7 @@ def update_plugin(request, name: str, data: PluginInSchema): @router.post( "/{str:name}/enable/{enable}", auth=django_auth, - url_name="enable", + url_name="enable_plugin", response={200: SuccessResponse, 400: ErrorsOut}, ) def enable_plugin(request, name: str, enable: bool): diff --git a/orochi/api/routers/utils.py b/orochi/api/routers/utils.py index ac4a892b..3067b3f5 100644 --- a/orochi/api/routers/utils.py +++ b/orochi/api/routers/utils.py @@ -5,11 +5,14 @@ import geoip2.database from dask.distributed import Client from django.conf import settings +from django.shortcuts import get_object_or_404 from geoip2.errors import GeoIP2Error +from guardian.shortcuts import get_objects_for_user from ninja import Router from ninja.security import django_auth from orochi.api.models import DaskStatusOut, ErrorsOut +from orochi.website.models import Dump router = Router() @@ -112,6 +115,10 @@ def maxmind(request, ip: str): @router.get("/vt", url_name="vt", response={200: Any, 400: ErrorsOut}, auth=django_auth) def get_extracted_dump_vt_report(request, path: str): path = Path(path) + index = path.parts[2] + dump = get_object_or_404(Dump, index=index) + if dump not in get_objects_for_user(request.user, "website.can_see"): + return 403, ErrorsOut(errors="You do not have permission to access this dump.") if path.exists(): return 200, json.loads(open(path, "r").read()) return 400, ErrorsOut(errors="File not found.") diff --git a/orochi/static/css/style.css b/orochi/static/css/style.css index 55482b61..65567987 100644 --- a/orochi/static/css/style.css +++ b/orochi/static/css/style.css @@ -282,3 +282,12 @@ main.view { div.wunderbaum { height: 95%; } + +/******************************************************** +DATATABLE MIN HEIGHT +********************************************************/ + +.dataTables_scrollBody { + max-height: unset !important; + height: unset !important; +} diff --git a/orochi/templates/base.html b/orochi/templates/base.html index b670c7c6..d3650073 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -144,10 +144,10 @@ {% block fullpage %}
    -
    +
    {% block sidebar %}{% endblock sidebar %}
    -
    +
    {% block content %}{% endblock content %}
    {% block offcanvas %} {% endblock offcanvas %} diff --git a/orochi/templates/users/user_bookmarks.html b/orochi/templates/users/user_bookmarks.html index 2d156827..70e54d6d 100644 --- a/orochi/templates/users/user_bookmarks.html +++ b/orochi/templates/users/user_bookmarks.html @@ -140,21 +140,25 @@ // DELETE BOOKMARK $(document).on("click", ".remove-index", function (e) { var bookmark = this; - var bookmark_name = $(this).data('name'); var bookmark_pk = $(this).data('up'); bootbox.confirm("Are you sure??", function (result) { if (result === true) { + + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); + + var url = "{% url 'api:delete_bookmark' id=123 %}".replace(/123/, bookmark_pk); $.ajax({ - url: "{% url 'website:delete_bookmark' %}", - data: { 'bookmark': bookmark_pk, 'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken").val() }, - method: 'post', + url: url, + method: 'delete', dataType: 'json', success: function (data) { $(bookmark).parent().parent().remove(); $.toast({ title: 'Bookmark status!', - content: 'Bookmark ' + bookmark_name + ' deleted.', + content: data.message, type: 'success', delay: 5000 }); @@ -162,7 +166,7 @@ error: function () { $.toast({ title: 'Bookmark status!', - content: 'Error during submission.', + content: data.message, type: 'error', delay: 5000 }); @@ -179,9 +183,13 @@ var bookmark_pk = $(this).data('up'); var bookmark_star = $(this).data('star'); + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); + + var url = "{% url 'api:star_bookmark' id=123 star=456 %}".replace(/123/, bookmark_pk).replace(/456/, !bookmark_star); $.ajax({ - url: "{% url 'website:star_bookmark' %}", - data: { 'bookmark': bookmark_pk, 'enable': !bookmark_star, 'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken").val() }, + url: url, method: 'post', dataType: 'json', success: function (data) { @@ -193,7 +201,7 @@ } $.toast({ title: 'Bookmark status!', - content: 'Bookmark ' + bookmark_name + ' updated.', + content: data.message, type: 'success', delay: 5000 }); @@ -201,7 +209,7 @@ error: function () { $.toast({ title: 'Bookmark status!', - content: 'Error during submission.', + content: data.message, type: 'error', delay: 5000 }); diff --git a/orochi/templates/users/user_plugins.html b/orochi/templates/users/user_plugins.html index c553909b..463baf1f 100644 --- a/orochi/templates/users/user_plugins.html +++ b/orochi/templates/users/user_plugins.html @@ -253,7 +253,7 @@ headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } }); - var url = "{% url 'api:enable' name=123 enable=456 %}".replace(/123/, plg_name).replace(/456/, plg.checked); + var url = "{% url 'api:enable_plugin' name=123 enable=456 %}".replace(/123/, plg_name).replace(/456/, plg.checked); $.ajax({ url: url, method: 'post', diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index a903359c..c2d5cd1e 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -215,7 +215,6 @@
    History Log
    $(document).on("click", ".maxmind-info", function(){ var btn = $(this); var ip = btn.data('ip'); - $.ajax({ url: "{% url 'api:maxmind' %}", data: { 'ip': ip }, diff --git a/orochi/templates/website/partial_indices.html b/orochi/templates/website/partial_indices.html index c2ddd9b5..4c759c98 100644 --- a/orochi/templates/website/partial_indices.html +++ b/orochi/templates/website/partial_indices.html @@ -20,7 +20,7 @@ {% else %} {% endif %} - {{name}} + {{name|truncatechars:35}} {% if status != 2 and status != 5 and status != 6 %} diff --git a/orochi/users/views.py b/orochi/users/views.py index fb468a22..28511f44 100644 --- a/orochi/users/views.py +++ b/orochi/users/views.py @@ -23,9 +23,7 @@ class UserYaraView(LoginRequiredMixin, DetailView): def get_queryset(self) -> QuerySet[Any]: mine = self.request.user == User.objects.get(username=self.kwargs["username"]) qs = super().get_queryset() - if mine: - return qs - return qs.none() + return qs if mine else qs.none() user_yara_view = UserYaraView.as_view() @@ -42,23 +40,21 @@ def post(self, request, *args, **kwargs): plugin_ids = request.POST.getlist("id[]") for plugin in plugin_ids: up = get_object_or_404(UserPlugin, pk=plugin, user=request.user) - up.automatic = bool(action == "enable") + up.automatic = action == "enable" up.save() self.object = self.get_object() context = self.get_context_data(object=self.object) messages.add_message( request, messages.SUCCESS if action == "enable" else messages.ERROR, - "{} plugins {}d".format(len(plugin_ids), action), + f"{len(plugin_ids)} plugins {action}d", ) return self.render_to_response(context) def get_queryset(self) -> QuerySet[Any]: mine = self.request.user == User.objects.get(username=self.kwargs["username"]) qs = super().get_queryset() - if mine: - return qs - return qs.none() + return qs if mine else qs.none() user_plugins_view = UserPluginView.as_view() @@ -73,9 +69,7 @@ class UserBookmarksView(LoginRequiredMixin, DetailView): def get_queryset(self) -> QuerySet[Any]: mine = self.request.user == User.objects.get(username=self.kwargs["username"]) qs = super().get_queryset() - if mine: - return qs - return qs.none() + return qs if mine else qs.none() user_bookmarks_view = UserBookmarksView.as_view() diff --git a/orochi/website/urls.py b/orochi/website/urls.py index f39dac92..fe98fc87 100644 --- a/orochi/website/urls.py +++ b/orochi/website/urls.py @@ -75,8 +75,6 @@ def to_url(self, value): name="diff_view", ), # USER PAGE - path("star_bookmark", views.star_bookmark, name="star_bookmark"), - path("delete_bookmark", views.delete_bookmark, name="delete_bookmark"), path("edit_bookmark", views.edit_bookmark, name="edit_bookmark"), path("add_bookmark", views.add_bookmark, name="add_bookmark"), # ADMIN diff --git a/orochi/website/views.py b/orochi/website/views.py index 37215158..71aa82b1 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -30,6 +30,7 @@ from django.template.loader import render_to_string from django.template.response import TemplateResponse from django.utils.text import slugify +from django.views.decorators.http import require_http_methods from elasticsearch import Elasticsearch from elasticsearch_dsl import Search from guardian.shortcuts import assign_perm, get_objects_for_user, get_perms, remove_perm @@ -146,10 +147,9 @@ def handle_uploaded_file(index, plugin, f): @login_required @user_passes_test(is_not_readonly) +@require_http_methods(["POST"]) def plugin(request): """Prepares for plugin resubmission on selected index with/without parameters""" - if request.method != "POST": - return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) indexes = request.POST.get("selected_indexes").split(",") plugin = get_object_or_404(Plugin, name=request.POST.get("selected_plugin")) get_object_or_404(UserPlugin, plugin=plugin, user=request.user) @@ -763,61 +763,59 @@ def restart(request): # EXPORT ############################## @login_required +@require_http_methods(["GET"]) def export(request): """Export extracted dump to misp""" - if request.method == "GET": - filepath = request.GET.get("path") - _, _, index, plugin, _ = filepath.split("/") - misp_info = get_object_or_404(Service, name=SERVICE_MISP) - dump = get_object_or_404(Dump, index=index) - _ = get_object_or_404(Plugin, name=plugin) + filepath = request.GET.get("path") + _, _, index, plugin, _ = filepath.split("/") + misp_info = get_object_or_404(Service, name=SERVICE_MISP) + dump = get_object_or_404(Dump, index=index) + _ = get_object_or_404(Plugin, name=plugin) - plugin = plugin.lower() + plugin = plugin.lower() - # CREATE GENERIC EVENT - misp = PyMISP(misp_info.url, misp_info.key, False, proxies=misp_info.proxy) - event = MISPEvent() - event.info = f"From orochi: {plugin}@{dump.name}" + # CREATE GENERIC EVENT + misp = PyMISP(misp_info.url, misp_info.key, False, proxies=misp_info.proxy) + event = MISPEvent() + event.info = f"From orochi: {plugin}@{dump.name}" - # CREATE FILE OBJ - file_obj = FileObject(filepath) - event.add_object(file_obj) + # CREATE FILE OBJ + file_obj = FileObject(filepath) + event.add_object(file_obj) - es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) - if s := ( - Search(using=es_client, index=f"{index}_{plugin}") - .query({"match": {"down_path": filepath}}) - .execute() - ): - s = s[0].to_dict() - - # ADD CLAMAV SIGNATURE - if s.get("clamav"): - clamav_obj = MISPObject("av-signature") - clamav_obj.add_attribute("signature", value=s["clamav"]) - clamav_obj.add_attribute("software", value="clamav") - file_obj.add_reference(clamav_obj.uuid, "attributed-to") - event.add_object(clamav_obj) - - # ADD VT SIGNATURE - if Path(f"{filepath}.vt.json").exists(): - with open(f"{filepath}.vt.json", "r") as f: - vt = json.load(f) - vt_obj = MISPObject("virustotal-report") - vt_obj.add_attribute( - "last-submission", value=vt.get("scan_date", "") - ) - vt_obj.add_attribute( - "detection-ratio", - value=f'{vt.get("positives", 0)}/{vt.get("total", 0)}', - ) - vt_obj.add_attribute("permalink", value=vt.get("permalink", "")) - file_obj.add_reference(vt.uuid, "attributed-to") - event.add_object(vt_obj) + es_client = Elasticsearch([settings.ELASTICSEARCH_URL]) + if s := ( + Search(using=es_client, index=f"{index}_{plugin}") + .query({"match": {"down_path": filepath}}) + .execute() + ): + s = s[0].to_dict() + + # ADD CLAMAV SIGNATURE + if s.get("clamav"): + clamav_obj = MISPObject("av-signature") + clamav_obj.add_attribute("signature", value=s["clamav"]) + clamav_obj.add_attribute("software", value="clamav") + file_obj.add_reference(clamav_obj.uuid, "attributed-to") + event.add_object(clamav_obj) + + # ADD VT SIGNATURE + if Path(f"{filepath}.vt.json").exists(): + with open(f"{filepath}.vt.json", "r") as f: + vt = json.load(f) + vt_obj = MISPObject("virustotal-report") + vt_obj.add_attribute("last-submission", value=vt.get("scan_date", "")) + vt_obj.add_attribute( + "detection-ratio", + value=f'{vt.get("positives", 0)}/{vt.get("total", 0)}', + ) + vt_obj.add_attribute("permalink", value=vt.get("permalink", "")) + file_obj.add_reference(vt.uuid, "attributed-to") + event.add_object(vt_obj) - misp.add_event(event) - return JsonResponse({"success": True}) - return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) + misp.add_event(event) + return JsonResponse({"success": True}) + return JsonResponse({"status_code": 404, "error": "No data found"}) ############################## @@ -913,30 +911,6 @@ def edit_bookmark(request): return JsonResponse(data) -@login_required -def delete_bookmark(request): - """Delete bookmark in user settings""" - if request.method == "POST": - bookmark = request.POST.get("bookmark") - up = get_object_or_404(Bookmark, pk=bookmark, user=request.user) - up.delete() - return JsonResponse({"ok": True}) - return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) - - -@login_required -def star_bookmark(request): - """Star/unstar bookmark in user settings""" - if request.method == "POST": - bookmark = request.POST.get("bookmark") - enable = request.POST.get("enable") - up = get_object_or_404(Bookmark, pk=bookmark, user=request.user) - up.star = enable == "true" - up.save() - return JsonResponse({"ok": True}) - return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) - - @login_required def bookmarks(request, indexes, plugin, query=None): """Open index but from a stored configuration of indexes and plugin""" @@ -956,9 +930,8 @@ def bookmarks(request, indexes, plugin, query=None): ############################## @login_required @user_passes_test(is_not_readonly) +@require_http_methods(["GET"]) def folder_create(request): - if request.method != "GET": - raise Http404("404") return JsonResponse( { "html_form": render_to_string( From dd68e3749ced7dd03750ca1e8e89b5ed1674f494 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Mon, 20 May 2024 11:46:18 +0200 Subject: [PATCH 52/84] #1073 wip --- .envs/.local/.postgres | 1 + .pre-commit-config.yaml | 2 +- compose/local/dask/Dockerfile | 4 +- compose/local/django/Dockerfile | 4 +- config/settings/base.py | 42 ++-- docker-compose.yml | 4 +- orochi/api/api.py | 2 +- orochi/api/models.py | 18 +- orochi/api/routers/bookmarks.py | 125 ++++++++++- orochi/static/README.txt | 2 +- orochi/static/fonts/keyrune.ttf | Bin 199420 -> 219680 bytes orochi/static/fonts/keyrune.woff | Bin 199496 -> 219756 bytes orochi/static/fonts/keyrune.woff2 | Bin 106176 -> 115964 bytes orochi/templates/users/user_bookmarks.html | 59 +++-- orochi/templates/website/index.html | 50 +++-- .../website/partial_bookmark_create.html | 4 +- .../website/partial_bookmark_edit.html | 4 +- orochi/website/defaults.py | 209 +++++++++--------- orochi/website/forms.py | 1 - .../migrations/0056_alter_bookmark_icon.py | 128 +++++++++++ orochi/website/models.py | 6 +- orochi/website/views.py | 92 ++------ requirements/base.txt | 28 +-- requirements/local.txt | 8 +- 24 files changed, 512 insertions(+), 281 deletions(-) create mode 100644 orochi/website/migrations/0056_alter_bookmark_icon.py diff --git a/.envs/.local/.postgres b/.envs/.local/.postgres index ddf23c54..bfb10230 100755 --- a/.envs/.local/.postgres +++ b/.envs/.local/.postgres @@ -5,3 +5,4 @@ POSTGRES_PORT=5432 POSTGRES_DB=orochi POSTGRES_USER=debug POSTGRES_PASSWORD=debug +DATABASE_URL=postgresql://debug:debug@posgtgres:5432/orochi diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c3ac67a3..9abf900b 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-yaml - repo: https://github.com/psf/black - rev: 24.3.0 + rev: 24.4.2 hooks: - id: black diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 6d345e62..102b2e51 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.4.1-py3.12 +FROM daskdev/dask:2024.5.1-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -47,7 +47,7 @@ RUN python setup.py build \ # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.29 -e git+https://github.com/volatilityfoundation/volatility3.git@a19dfb57a68cc7efc8926d9f6e7c24e5a2dbab9d#egg=volatility3 \ +RUN pip install uv==0.1.44 -e git+https://github.com/volatilityfoundation/volatility3.git@dc7a3878fa39156d89d567c3e823f1956675f192#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 60314eb9..7aa05de3 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.2-slim-bookworm as common-base +FROM python:3.12.3-slim-bookworm as common-base ENV DJANGO_SETTINGS_MODULE config.settings.local ENV PYTHONUNBUFFERED 1 @@ -65,7 +65,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.29 -e git+https://github.com/volatilityfoundation/volatility3.git@a19dfb57a68cc7efc8926d9f6e7c24e5a2dbab9d#egg=volatility3 \ +RUN pip install uv==0.1.44 -e git+https://github.com/volatilityfoundation/volatility3.git@dc7a3878fa39156d89d567c3e823f1956675f192#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/config/settings/base.py b/config/settings/base.py index d285b5ef..65eec6da 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -91,18 +91,12 @@ ] -if use_ldap := env.bool("USE_LDAP", False): - AUTHENTICATION_BACKENDS = [ - "django_auth_ldap.backend.LDAPBackend" - "django.contrib.auth.backends.ModelBackend", - "guardian.backends.ObjectPermissionBackend", - ] -else: - AUTHENTICATION_BACKENDS = [ - "django.contrib.auth.backends.ModelBackend", - "allauth.account.auth_backends.AuthenticationBackend", - "guardian.backends.ObjectPermissionBackend", - ] +AUTHENTICATION_BACKENDS = [ + "django_auth_ldap.backend.LDAPBackend", + "django.contrib.auth.backends.ModelBackend", + "guardian.backends.ObjectPermissionBackend", + "allauth.account.auth_backends.AuthenticationBackend", +] AUTH_USER_MODEL = "users.User" LOGIN_REDIRECT_URL = "users:redirect" @@ -244,6 +238,7 @@ "root": {"level": DEBUG_LEVEL, "handlers": ["console"]}, "loggers": { "distributed": {"level": DEBUG_LEVEL, "handlers": ["console"]}, + "django_auth_ldap": {"level": DEBUG_LEVEL, "handlers": ["console"]}, }, } @@ -251,8 +246,8 @@ # ------------------------------------------------------------------------------ ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True) ACCOUNT_AUTHENTICATION_METHOD = "username" -ACCOUNT_EMAIL_REQUIRED = True -ACCOUNT_EMAIL_VERIFICATION = "mandatory" +ACCOUNT_EMAIL_REQUIRED = False +ACCOUNT_EMAIL_VERIFICATION = "optional" ACCOUNT_ADAPTER = "orochi.users.adapters.AccountAdapter" SOCIALACCOUNT_ADAPTER = "orochi.users.adapters.SocialAccountAdapter" @@ -281,16 +276,15 @@ # LDAP # ------------------------------------------------------------------------------ -if use_ldap: - AUTH_LDAP_SERVER_URI = env("AUTH_LDAP_SERVER_URI") - AUTH_LDAP_BIND_DN = env("AUTH_LDAP_BIND_DN") - AUTH_LDAP_BIND_PASSWORD = env("AUTH_LDAP_BIND_PASSWORD") - AUTH_LDAP_USER_SEARCH = LDAPSearch( - env("AUTH_LDAP_USER_SEARCH_DN"), - ldap.SCOPE_SUBTREE, - env("AUTH_LDAP_USER_SEARCH_ALIAS"), - ) - AUTH_LDAP_USER_ATTR_MAP = env.dict("AUTH_LDAP_USER_ATTR_MAP") +AUTH_LDAP_SERVER_URI = env("AUTH_LDAP_SERVER_URI") +AUTH_LDAP_BIND_DN = env("AUTH_LDAP_BIND_DN") +AUTH_LDAP_BIND_PASSWORD = env("AUTH_LDAP_BIND_PASSWORD") +AUTH_LDAP_USER_SEARCH = LDAPSearch( + env("AUTH_LDAP_USER_SEARCH_DN"), + ldap.SCOPE_SUBTREE, + env("AUTH_LDAP_USER_SEARCH_ALIAS"), +) +AUTH_LDAP_USER_ATTR_MAP = env.dict("AUTH_LDAP_USER_ATTR_MAP") # django-cors-headers - https://github.com/adamchainz/django-cors-headers#setup CORS_URLS_REGEX = r"^/api/.*$" diff --git a/docker-compose.yml b/docker-compose.yml index d6daad8d..73be38e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -121,7 +121,7 @@ services: - "6379:6379" es01: - image: elasticsearch:8.9.0 + image: elasticsearch:8.13.0 container_name: orochi_es01 environment: - discovery.type=single-node @@ -144,7 +144,7 @@ services: - 9200:9200 kib01: - image: kibana:8.9.0 + image: kibana:8.13.0 container_name: orochi_kib01 ports: - 5601:5601 diff --git a/orochi/api/api.py b/orochi/api/api.py index 8dea779d..f008272a 100644 --- a/orochi/api/api.py +++ b/orochi/api/api.py @@ -15,4 +15,4 @@ api.add_router("/dumps/", dumps_router, tags=["Dumps"]) api.add_router("/plugins/", plugins_router, tags=["Plugins"]) api.add_router("/utils/", utils_router, tags=["Utils"]) -api.add_router("/bookmars/", bookmarks_router, tags=["Bookmars"]) +api.add_router("/bookmarks/", bookmarks_router, tags=["Bookmarks"]) diff --git a/orochi/api/models.py b/orochi/api/models.py index ad766799..a87d2fed 100644 --- a/orochi/api/models.py +++ b/orochi/api/models.py @@ -6,7 +6,7 @@ from ninja.orm import create_schema from orochi.website.defaults import OSEnum -from orochi.website.models import Bookmark, Dump, Folder, Plugin, Result +from orochi.website.models import Bookmark, Dump, Folder, Plugin ################################################### # Auth @@ -210,6 +210,13 @@ class ResultSmallOutSchema(Schema): ################################################### # Bookmarks ################################################### +class BookmarksEditInSchema(ModelSchema): + + class Meta: + model = Bookmark + fields = ["name", "icon", "query"] + + class BookmarksSchema(ModelSchema): user: UserOutSchema = None indexes: List[DumpSchema] = [] @@ -217,3 +224,12 @@ class BookmarksSchema(ModelSchema): class Meta: model = Bookmark fields = ["id", "name", "icon", "star", "query"] + + +class BookmarksInSchema(Schema): + selected_indexes: str = None + name: str = None + star: bool = False + icon: str = None + selected_plugin: str = None + query: Optional[str] = None diff --git a/orochi/api/routers/bookmarks.py b/orochi/api/routers/bookmarks.py index dbf0f0c3..03f86910 100644 --- a/orochi/api/routers/bookmarks.py +++ b/orochi/api/routers/bookmarks.py @@ -1,15 +1,78 @@ from typing import List +import django +import psycopg2 from django.shortcuts import get_object_or_404 +from guardian.shortcuts import get_objects_for_user from ninja import Router from ninja.security import django_auth -from orochi.api.models import BookmarksSchema, ErrorsOut, SuccessResponse -from orochi.website.models import Bookmark +from orochi.api.models import ( + BookmarksEditInSchema, + BookmarksInSchema, + BookmarksSchema, + ErrorsOut, + SuccessResponse, +) +from orochi.website.models import Bookmark, Dump, Plugin router = Router() +@router.post( + "/", + auth=django_auth, + response={201: BookmarksSchema, 400: ErrorsOut}, + url_name="create_bookmark", +) +def create_bookmarks(request, bookmarks_in: BookmarksInSchema): + """ + Create bookmarks for the user. + + Args: + request: The request object. + bookmarks_in: Input data for creating bookmarks. + + Returns: + Tuple[int, Bookmark]: A tuple containing the status code and the created bookmark. + + Raises: + 400: If an exception occurs during the bookmark creation process. + """ + try: + indexes = [] + ok_indexes = list( + get_objects_for_user(request.user, "website.can_see").values_list( + "index", flat=True + ) + ) + for index_id in bookmarks_in.selected_indexes.split(","): + index_id = str(index_id) + if index_id not in ok_indexes: + continue + index = get_object_or_404(Dump, index=index_id) + indexes.append(index) + if indexes: + plugin = get_object_or_404(Plugin, name=bookmarks_in.selected_plugin) + bookmark = Bookmark.objects.create( + user=request.user, + plugin=plugin, + star=bookmarks_in.star, + icon=bookmarks_in.icon, + name=bookmarks_in.name, + query=bookmarks_in.query, + ) + bookmark.save() + for index in indexes: + bookmark.indexes.add(index) + return 201, bookmark + return 400, {"errors": "No valid indexes selected"} + except (psycopg2.errors.UniqueViolation, django.db.utils.IntegrityError): + return 400, {"errors": "Bookmark name already used"} + except Exception as excp: + return 400, {"errors": str(excp)} + + @router.get("/", auth=django_auth, response=List[BookmarksSchema]) def list_bookmarks(request): """ @@ -21,6 +84,64 @@ def list_bookmarks(request): return Bookmark.objects.filter(user=request.user) +@router.get( + "/{int:id}", + auth=django_auth, + response={200: BookmarksSchema, 400: ErrorsOut}, + url_name="get_bookmark", +) +def get_bookmark(request, id: int): + """ + Retrieves a bookmark by its ID. + + Args: + request: The request object. + id: The ID of the bookmark to retrieve. + + Returns: + dict: A dictionary containing the bookmark data. + + Raises: + 400: If an exception occurs during the process. + """ + try: + bookmark = get_object_or_404(Bookmark, pk=id, user=request.user) + return 200, bookmark + except Exception as excp: + return 400, {"errors": str(excp)} + + +@router.patch( + "/{int:id}", + response={201: BookmarksSchema, 400: ErrorsOut}, + auth=django_auth, + url_name="edit_bookmark", +) +def edit_bookmark(request, id: int, data: BookmarksEditInSchema): + """ + Edit bookmark. + + Args: + request: The request object. + id: The ID of the bookmark to edit. + data: Input data for editing bookmarks. + + Returns: + Bookmark: The edited bookmark object. + + Raises: + 400: If an exception occurs during the process. + """ + try: + bookmark = get_object_or_404(Bookmark, pk=id, user=request.user) + for attr, value in data.dict(exclude_unset=True).items(): + setattr(bookmark, attr, value) + bookmark.save() + return 201, bookmark + except Exception as excp: + return 400, {"errors": str(excp)} + + @router.delete( "/{int:id}", auth=django_auth, diff --git a/orochi/static/README.txt b/orochi/static/README.txt index ae4b3062..51fe47c7 100644 --- a/orochi/static/README.txt +++ b/orochi/static/README.txt @@ -41,7 +41,7 @@ # Keyrune [MTG icons] --> https://github.com/andrewgioia/keyrune ---> version 3.12.2 +--> version 3.14.0 # Marked [Changelog with MD] --> https://github.com/markedjs/marked diff --git a/orochi/static/fonts/keyrune.ttf b/orochi/static/fonts/keyrune.ttf index d6d048647cb31e7e647a3cdabc6370a9da74e0bd..530bbc2e8b1484f19f48d2b634d33f2f1cf0c36d 100644 GIT binary patch delta 26531 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 z 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 Hv=jdaHnJH& diff --git a/orochi/static/fonts/keyrune.woff b/orochi/static/fonts/keyrune.woff index f48ba64db29fd66422a8f459e6e9d9c2cf3437a7..da9c8d78e58981d65667182c9fe38c14ac46bd33 100644 GIT binary patch delta 26561 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 M%!=Z_u;lapH<*NhF8}}l delta 6240 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 Za&l7h&K){-a#xJy#fHKLjd|;xW1;Y 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�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�i;UwF;g4zaRPtE*Yue@7vW zUxKmzvA>oNk0uoNv7LgwH^)2Xlp_bn_dtCFwx@IKpA;wklabAVb^86>?k;?sA5WyC zma+GFOFYgG(XY+|s3v%cfc3!0Ru(T^FdjqVbEIu5ftq@r=UgJ9(@HV{*fNcg6{x6g za$>V7ib}(DPpDf9BIeqGMQoT3LAhE>rGg5nz$O>^Sp+&rxBn7LcMHI-No6nRVQb7I zWTCQ%zi86%R4}rNHmcfq4vu@UIFBnvhm%m0oRG(sh)i!L(#EteXlf`D!oF+=c@!Bv z>SVb*&WPrnO%UvWNtNc*F;j;PdnNKPu=swyW8GdiepO;xZq|Ak0;@e;ZTC-YbZHHq0DSiM=l$uF}$rfC<>2!?#KY8Zw1&8v@{rn;%xjyUSd!WYt<)3mX?04YG$ zzbrR&#X>ym4ra|eEnL*ta~5aL;TRi1B=Ag|Sp``Q_3KhQyidxh7#==W=9(OxZb!^= zD{xjkT;C2;TGCm<%<$r;OtFeBu2Pct=H>g#ti+q#eV}TEUV7V%(I)1eK<^b3M(@C2 zpl?&I&H)D)h05e+2X?s{`Dv9*w`0A>iFxfew*pSIHu{+^_fFNJz{^ohD8iI;k~A#vIght9O!ouK=$L0)_)5W zG&Eo4ZC`v@uy5}Eyls`#_58 z-ovlSt(*K0v-Z*_W<}!F-uuzTBo7F}ojyyipETKQOE z(>w`0NlAF$cq~og;!r5ylaIH;wNAz08IfrO@TPY)eekcTR90`Kr*|^o?lm-v?y6j2 zLdDHT>@zANdEedZa>$E(&n=_(LpR3rDosbWoF~CeN5Tr<+O-+l@8`DQBkp@^WzpD8 zURC7J!WCPyLocrvGQ%6^H<#7Ax!z4Q|2s zV0<*Irm2Pz=Z>AO#cKjeCk}ubkz6j1<#HYhTwfiP@8Ygq*OpdHf|pi|d~g|v3rYl` zk!MNr9$FETrnJ7U^I1Z>G|I+>5?qc)9GdFHSxcqvb4!yoH7S!TBy0};mvgIdCdStn zK@qu#fBFQIlPu-jcmKkf)g^!9H>Y1HVeY1YAOy|zRA`jMfwqEi)kN<1WM3>|{?-M^ zO{0~Ou?hmES_XMEp-fXbaFqyUssb3VH05lTtF(PF^`)`6q<<2aEYfwUWELF3r?Jn} z2}x`ErEB^Dx39>6U#7R@Sk#t%F!t*x_D@BoeeG;-r-E*12nz^yCQOU8mu22c&Qee* zUrA=Y7q2He96iANUE_%NmVr9ba8}mm507UcD3f4{x+$$euBlN3m^e_cAw5apEhIoM zqS`+C<6jo@U8aC^9qpavcI37Rt53P_u)}#Q*$ryz{fMd)=vPFd&u!TN6LMW_4&~wUs{Q6 zH{VAo0CGQdB?s3g$bzeBj%|A-HyRU;!FALxO&s_RB~RG7rHbo*%m zxIWs67bbl&^k&OsAb@%;Qg62{I6<(Tu z)(ZDK^Y<&_^Xk#r0he~CX9+1#!p`n7o^0+}v^67GHGm;7U~K1Xz@D?QT%bQsJ7ikOO)vm1n$}sc?eb5FrgJxa@!+?6&NE#||_< zbOcn7p3=lE?LdtMSOTr;YDaSX@^Msz&aa2JEfkzsJzgd|Xy}h{-^V}WVIo4gaz`wU zTF&>y)6cT)#2Fp>>EW<}QJ5D_Zji&1$~PAE5c^Mf=i1v!K_qx6UW34=9kP5(s(e?4S(Jz3R9 zJ~(L4JYBz6T+}Qw)T#Ol9VZ%=y2R+lB^Bc)f&v@rm_Pf{^h^)E>uKyO%M|Ph1wz5F zSR1!lQ2KXyGD<#qo(SH4>=b{c3?itIMJxSvzZ&S=P{|1i))k%|pA2mNoNt5y&njL2 zv^L^ZfB`(E!47g_|D+;Ng<_8@iV8B!2d1bOo|i%W&Nl`5|K)NdM3H#0``y4K>K@fK z@vA14`2N+}bC1fESA*TVHBrSFBzo)kd>9}Qkr|}!eBVTR%xnI`LE*`>&wUR6J5*fX z^qQxMMy7%X%PB{?e07%3o?Ka%lA&_#|JIZBZ;H7aG$Q0GR0D;_a(Iz@d`J1yMzF+C zi&@t{P^S$XbiIJ5Q=Gn6btn+WdvpS$ISF)wQDwBcwg;Yv+VZ>hgSGOs>@I(M@*C`R z39zELygVPRY=~j$CgjV^Bx{Pg|2tpA-zQbcTKSWNkFEsd4jqlK(wt$WL9EgT_0Aih;JLWW`M3@l zXrj5yK85E)3#35wy8b9vsLFgS4Cdpa(J+{#;sB6Ibu@`^r=t=bhMVK-96P4l4o}J0 zX_OLaR$TNi>%Vz;m+*bvmV$z=?W+>p-CaKvPsKHR2V7^5{E+7Ap1GPyM3%5xTV!`J z2lxQ&c~^;q6+(ntU<~aJi(!;7;SeMUuxPmoP@I#VvAo93s;*{@3$9xqzBeJG4JcEE{nVpW+*UnB+E{!N;RF4BbEb^l7xh5jE7Kw+EMd+ z%@+&1ZxMo)yzizqle(K=c84k7$@co{`%tt>Q;QW&W%HqgGMcrsE;?npJichfp?5o zpU1nDeW>LvgX?riRl(wI{6A`{BF7#8FK6+B z&f+UP@0LvRC3QYhebm7HZ#sKx_0#ZHVF!HYup~EMBm<}seMVSyd;|yOW zKtZ>Jf@zkg0l)%M4FLUEk`O*(m1o8;G%CmC+OwRb4zAe-Uv)Mqb?#81Cjq%{2&{$< zvJ3dfv(P}!quH&HX)H2uE|1-w60>i3UXFC>=1bm<^~P0G85U;$%Lob8?MGQ5$_Xuox3@vJL+_&p@VQ z`~omm>T;2Wpa5-Fo&#u*FJ&;V}iL4xzxkL>^0CPJd1lpH9N7zH$m$Aw(>u z<7S5%j}~@)4F9O(0AGqMtZ-P#HGOBMJ}|lY!3BP6QMGoZe03_KT36izYfM=E)5?BT zD_@7GzQSGNaDKtBB5}Msx#T%4NWnEReUgp=vL@`|(v9u*ey>hXWDL(|k0lN2%Wzrk z)r{~I_yK>SrVrqECw$ub-Pg{Yw-A#c%T1#{yzFB#YdDkBs0`sBU9RH`Q3G@j4RyVU zqRpc+NS4$>))N|pq;>}shfjck;?UDrGLmewA_cJ>DE_xKP{?XJGeF3>l?X(Sz@0Xr zARuBr6)DZt>$@tV(p1XLjPpuj*-NW4aMGgE^xNfRz_W(>|I77Jwp=?Op={@B6sr;U zGB?1_YCM;DGoKfL& zlmcSfW8?97E^Fn!?O)K5d&~VT@Lm*Cv$%Ys^8TvkbSUgckgrHlQyGpc1Zoc4Z&4#6 z(_hlGP#gR2O0Z!R+<6wnmz?!8+y5S>zN`!ei8iq8SNZ^V6)Z0z{9z(29zTS#oa?%W|BSP563dbwN1kOyrpfyA{GbfKQs|HObb_sE5MEy1Gq}E#h|VxBEtkM zx_dIanoI-k8%sp(9*D|2DR5|abLkX}$|L3qT1z(XXhJl`Z2a-Fn6)vB)(acN(#C?# zCRL}&-Gm8mkc^8|D8C3&=*q73 zO-aAMozE`U#nxN&_~_yg`8|xD(&{^ON~51zszgIQf})RCY*WS(#E{0UdD?5?TK>(@h~JI?bJlF zPQw=R>7A{XrtQiDKdB{s2j>S%NR9@qO*)6ehN|fjp-h1MpI`( zxI`LwV_LVvo5+_BdV?#rJE5AFjJ%;G>taV4?AgeRE%z($NN z`fAN01fOx_R3?FW21Foq?tqZb9hs(%q6w#5c2hh;Yw37L_=#=R95kE?H*)vDrW5UB zLThrHP33h)H{A60QHKhjNP%1$nHVqIbZyS2IJJGhtu_AMg=su3cthqPue$;jD?;I( zP(YMX@8C$HhC`r~(ChLXb=WezCYFr)97mUl$;3_l`lM%S*5P$wzyP|dV)7SI1lP}o z;H0a=vDhW*QY`dBwsS3(TBtF@`^-9;xnv^<0f_RTkRJPvo3&x86l)S6xxU_3x0Mc9 zM0`sPosu4-$Nq9mPWKxeWfJf*Zk#3&S@vuRClZZgeMLlF+0 z*s*n^HW((2-iM5T^#pthrqCm2k(%d<*?vI|1?z~uQ9Rx&yYUy?HwL zwm1vVlj=zim8YER=#RS$M(_qHZb5pwcMu<+Rsww#Mm_s0cHk#tUe7H_f^CImg(Dq$>&mgBEDAc=2=PH=! zW@BpKWUfY2T>Osk*fFWe{Yq}1G@V!Qm~T4mUAF{r%z3IjH>fkZJM%*vuM%Zu86NFl z77{eG2XV-cQS_~()p9D84;X>$n{Fv@OZ8N4R{cL>(A|IPxcwQ;7`i zOCa7wW?N7SIoEltL~~@L6D0_(F~z7p1T5Sc&S-7t8mA2BkjWEHD=}oK-O1SDvAhzP zyv0sXz$7eKrvBI|h<$_K#{pnD-mn7=r!72#l>}Ba*#WJMK(?eqhKEwRK7s*?_SjB% zCVnX*Tcm&{O*YWo$U-`Hq)}iat0b2ar!A;&CtTmQ15M1>Fbwk-q|x9f8#Hv&bE_ESq&MMYEQ%ne&_lyuA7F{-T~P6u;A2azyUWg+&`ID8R7(83c2;@kZFi_V77a1JrG5u;6QODwE5e zmor>3H2ZULlNt=PDGNmKj$YQXPuPI<5vCGF7o3hg)vXDJ{i*~+EC4M z!%y7N+LyTD(bz}TX;sZV=Z5da{8}S+2C%m?oPtx^>w7a)^Q-Nfy-KEF8b=ao01n4a zXfM4{-~ofH$LN@;NeVNwDV8Kp zS|rD=5J~BW;fmn1Xpe0@`83=m=1FUo*o=kCv)COpHoRV1U*SFowP&YJF%x`R9@3Ar zEB8N}IDCxH=$yX$tofkIaYbq$kosiXM)ePM5 zW?1H!Ho_rlg;A+)e{r9~*t4)DT82gL>C`W}ymy*Yvz$YaOIKM)| zI$!{o24+&fEDBMCR8wt1j1n^u@JHst{Xl&sl*8v^-3yRubgO_x{o_7=g#wMuy1{dk z+Y2MhRY3mqsnju8p0vQv1h?tb*J)UI(<#^j)*v&ta9RZmA@GPj@8ahyy*j0Tt(5h1 zvOs_AX`p3A^oesDz{hn>ipXegIsL~EZ$nLf?SXs#e9|{RCC2fhi+wp5dj9amja8T$^Ufw!|912WBRnniw|7K9!<(IE|NH{XJ zQBT1VKW4-#?+;lC2Y<4Ar?5jgK>tp z2-W<^CQZhW1Jbjswh=zE5W1MwyiLz#qEV$Qci?~Q5{r-w=p1U5VkJ-LMZeo09F7}BNX7tzFas`F2%tI%E_Gct_=(IP#~Cu>gOVOj_SwXk_sr?<$9_?8hT*T; z&fdq7G@=5ZjV0-{nGhT0%>0|#5jtiGX}+lc{l3474vw0aSs;PT0^&zGCU_^}P*z$i zV_9DEu4ftl8yYDY!FKXS(7-Ndrl<)odWK!|b60Lc0ZUK7W{{Q02?sRsk(9DW-~%CC zM+el!8?n(ETuH|7X5JOuyUB^iUe5E`ALL&qF@R6`X&DBi+$+f@_Pq;?)5ghvKGyop z+0=UL$=XLFh~AymK()u-3A1tE1+G4H{CzTK4k9cWuDr9_y5M*THA{{b{6u?Jf09aD zUIQJO7&>E_WgczisD z$DksF?vWClg3^h&*3ooC+4pkNB>R>tIy<~QK2u*RqVSZLt)mGem(qkPG>Y<>N-n$% zTUXI)+eZ9QmUUZbuxxzbTq(p9!*j^3s)CJSA%%yjf96g0PC#-xYl7=7un&Z@Ty`F zU(#Cq^!Apj(#P_zG?aS;cf;{SUFRR8obN(b1x%_qTmUo#fBX&z=DL#0x9NY%7rw+C zZLK&gqvlGfW&hZcd~4d^D}^)%i2@?P>TX&xeF1B5#vKSZWrp7ll&F>b?lF8!-1y7{ zN52kb*SEwzq$~0{c{hE#!002OtP8-uXdypQLmLfEW@g?{@QGV}7C7V+BE=F?F))bx z9c3R+qW#@jIcytp_ixq{rzAVv$dL;am*RhSr~$SmF;Ydum-5F*pf2KKv||ZVn;15} z1i>a5f8Td|(Ongh1Is)ejvor*+&VNz)+}KUsJKbkd)l?Mjj~xTwlDe=2AB$@%@Ym7 z0mlK1i^4yessJw=@1&)51K-^Bo+^RhSt&9o&f$lep)EudY8x&nyi3sx!lkXCsD2N* zKcN6c1ZQ-{*=?=3iCxX^M=e{MRmD*k8<|Lz<2FTjl2`-F`l9v;TY(SmW+9Z8_=7j;?I%t3(NQf1fwx!dTXY4Cz$#Im0G}cdS5dIL zFjRSP&_PL_9oK){HF}5eaaEVN!Z6IK7iO$Qk@W(_RjXDtgkZ81k=_ZF7e2oDbYJEdB3Yhiu zW0b!n>vBgGQ-u!y%A7B#>tj;Ay_4SYig{1hGMPc=d=g?W;eLM+42vO&FR{kJGISdb z=#c9hwITQHl8>Us4{heP(s9hO4BC#g`xD8b;!ZGh%u$PvCz81H(MzpyQ5Ppl{C($K zs}hFe?#$eUA|6vai)2^*{##+*ClXN5^4omYB_uWDH&o6$TigPm;m+X@@ciLe4iKD^IBo(nkSCwd;F(m;5%7ll}iMo-XKbZM{N zzqBi8*DAEL}M2 zn4fTd2|}zJg;=`=IZSl<)Psi9j9PHK(SenEI3tvCD>w((fy;^SE-ut|g)i*cKDNkzn|PVG5K)r+C)RtKjy^ zytlxPM1JW)UoK6wF=8c&fmq)-fKFrw@RDTFX+Mcuf(^bIQ`CuD=GE4Ug)`RM##$n9 z<)%`_O-)|06tsxY9uWvMUY3pnp22D&Jx;_NnEM12CR^oV7oq(su-Mr+~!(V>Pg8qE7|*Ch()MTN=`D+L2DB`9_{C zGr~A~D5WZM?Iawa98SjjG%qaJT|mj{kpR2_+|7QLiMKFu@R3C%W$MqVP`70`(wr0q z>r6D-F7g3B7|c?lr@7CiNZ5&=Nn7||Bs69Vsa;5w1^jI|(srO7hHC>2b_fSZBvm*n zaBPiq?UQ&7J0AVkvFD==A%R13`KVpydRg0$$OgZp+qHdt^A^WIYR%j;?QBO&f?Y0nbL-% zv5wOwQ01!%11!tEmXSrACan{%%@@3{H!T|SYQ2BLNX9Ky8Z8I%T8B3woJ!X*upsQN z7;;?*t)sA_U z=3)<{^~B8J*9LV_eN5g&1d(PhUjwXt^3j!vl<}{&BCK>7p5g;@EzcQ59ywoKn$%!*LsPCpICTsZ*C#yOsT0r>3A!i5$>oyY# z%K1pPD%eO8U67>2?oD!%aYM%cVFwYvyvIYSm#EYS>f~i$2H=cxoZuWRFP2?GTWzpCWP z3@vw{(I^#k5h28^bf|wF&F%tn554&@-eBV_=RWijR9yKS*uhc;1r94(mfO}ej!L75!4yfCAq#0E0M*Gm zSE`dA=YplTPAlSLInqv;6zXpV@QwIRpw4~qy?jtNzuBGk_HZ|; z+ErZ?zS;{0u8CeJ_bxkT7s5%^3WU(5Bo|y`Woghr05St6mIy+}by#pGMv$anlj6*G zCF&pErUnWe3y+?0ecmgW>fr#n3l*vxQ_;|rs_2T`zfcymr*a@5yaA<((SaT)F|tRc z)Ex2y<&S&d*^HsCZxB=~6*7$E{OT~oU0GN#imM39B8-t%ogxg;Q3$tb5fzVqCsXRo zX^)H7`rFNRi+lq=O>K__hghbJYQ4(Cb#PWSA+Q$p@s1x{6mz06f-$|b4rfN%qn_tx zD3BOV1uC=oZ5(kqx;H!6P88O7!~ESiu&g5(M$^^MD-H&+yo)1@!p`Fs=Hw=Q6?Lwy zA^?|ckNQVG{(gi-$BbA{^WV1Mw;rqTs-F7!?l+XI>dhKNN*l)3u<{P&Kp$~f<`*oK zMG-8~W0F-@E^>ou1PlkxgnoBa-hhYNc#VydP#r2}Z95cQt@_WhreI4&{<-T~ZA290 zacr3}y?9cKujgZI_xNlnUaXq&G z+u!^=*wuCdN%XsKWD~cMKzg=6_Sedd1G?|F{qTL{%zq{wm%+;BQ)>7Vk?0~VrI0QU zk=~Y7GCM95sQyUfB9&4PS<@9h6lZzu&w`XhS8qcjq56jT+Q3}b$h1<+07qTr-ZQ0M z-L2&Dz@*|0MaHrHp-XFN6EUgXpn2ld9Z7u8` z+>@jXHbAVPF4UrsIp>0sO8i6)1a^X;b$FhlI}0;rYMcPPYkZZ=K~*ZzZdnw$mNIEw zLUORo5riQ&ff+bRL|?Tbt~RcI*&CbfgG+15IHI5_-ih~Pc9ziT=b^fnq!HVA6OJGx z%A>A-LX*&mx($t6iwzY}^U=ph(A>B%k%J;Bz+1@e8hEy7+Hx{aO`a$G?p^3rxEflm z{f3TUGpyHWz+^f=_SxDQ|KTXO9wwP&0!$1SkF3$l>7Y$1O z&+!rXqKoK`W2GfKXfBeYwRK|H(oPkY?<1)-T}yHLuwCJB27FRI4;VvLjTro}Dz4 zn$!E@O0?p$R<{{Umq^6c?aXOS-0#8ye7&F9fF>~5SU3LAwXjd&({HEV%*7X?$%%`F z+8#MX=*lI47BW95$?*EvkZbi%pNMu%1Sn|lxjwTmJ}oZax1c$)(jL-q`BAZNL3aMC z{T!^QQIg`q8u9R`SkG|8HHO8KNyi#FRB!IU%?ih&G2Xz{z6%>Wchsg==FlE)sToKW zxxP5gmU5i?v?JLtl{YwTcCi(y>?m*YPr@wF-JyRDI>Ywrn?>Fu05s6|2>aC;4GT&$ zR9h|A4&?4hi47abP=xym{AT{>l!%`@(y=V^2}o09-%KcVobZB z&KwHuA?aMM*X%S3Qc{BwO)x3LF3J-0t9cgp$+o%!=Y582I<6)_ZAZpVW2jeT0n>A& zw?u8^pxA{1L$oNRa;;Y2JTw^yHgd~+z);xeDxGqU-y(BqH()tDRSC-Tv*7i9bqD=( z!teL%K9c1nH%;?<$LW`K*!s06h6NISSX(Z)vTG&%67;*|&TRCqh%(mXw^1p{l9C=5-M zPnI%L9^>2N1|#a_(cDsCMB@^zbzE6azQO?_PLsCcZiT+w`UPdV2f+?yf^Lwr#(57t znzGTbI*NUs%Ig&FlNG3vk41!tX2a^`#TVk;bkTW7uf{JWsjK2AhvKKH))^bqWDVPR zjhXQLo{k*ObNBFvJ%^xgmZ&7C%$kmr{3Ry1f2{n%BgmEwXH~^dOxfAGBo+*n=iocYDC? ztX$t=Nvg$Xro+0GqBa~+0tX9Yj{k%N%_QI3RhJH2xmm;{`co)lW~Y!4G3z>9Zm{m< z$5S$P8leYHZB+!WQ`l-f-66e{@*TIF>=yHa8w1tJdrNE9C-DxHek>Q8rOHg@6typ( zE8WDVc;%Gd+AbG)`SAU`c=1@73a_q2h@!7;*D9rmP3_3!oGG%hSR2=KdzQ-9FR8HZ zyfu;S*T#sBzrR=`_jM6lECMqwqiFM&nP3Tx#7PYoGdiELB-vSqyGG)ulxt}D^UN{r zIMz;o--m+vb|^(GsS28fZ}P+!ib;+Gj{nb6!GJgj>q3HWz%9j=Auv zlsNUyBK0{ALrx5s(K&LX(HTQCORbc9HDP=gM=m(un_MsNOXDI+bq{%VfCVhtO3;YL z=w`B|qn8*T7jBD=riX8R)3LI*WTUeIdsflk^~@h2zws`8ACpH-7odda!L3LtBN z+z!EVCKa5eH#s54QQQlTazxHqv(m+eNIjQygZJHa?y7Hxe^k$t^oUK~B`kHrDsl4e zGEd0{Pp>@)ic_Ma%^w~;@IJ&x2`kjCAXfbnqgkoDbJc*TPTJ<4(d+6XI#z|*DXbeY zVI-i-n?;#2+)l4FYU(ni6qAdtqkAc^Hi?%X&3c}BV#mO8tL;d$yS%8<>~qzmH{xYCF(c3oG-4_#1){w$!u9(X<&Trlb)gNRyDbqJ&!7KEY5c0yIg*o9AL^K&u_fpiF z7|-$%9g>I-Ve{ieT6|SoqC2L zSkaC9>Lo0DdJzt_!Z7^SnDx&W&UwAdjtSG9yi6>qFZC=1>OVD@bu(N&%*)qK=)Q%E zzy6vTdIoyJbEXH8>q(wX{>WlWw)G-pZW+ZpK=w5rm2MLb>g*_qZ_fmJT<+YN0>X{>fMfov2dbbA)c?IN$uGK6a|+G4g)sh`ihATAI?tHz1(r&0Y$tS z|0LX=p6so7BjSr5e>W``V9Vf%jVY%TH%VjDnHQvrInh672-y)zzEG68s!?FWqHFqGI>tcv5b|B8<2(Lot%=rzs**@t}$TLjhAj;~jM#cE{x`8*`! zbJ8fKk!oCqh0AxLyu_pria1y}H)=%U*Rf=?856$zO~%7E6rfmQMPr1WQ%LYlfn}C6 ziz5#+P!ou6>7`XpOnmS%lD=FqXWU;kKjGnRMmttgTmvzPw^qp)BKcyp#9QD;-5zh! z0kNHQWo`Jw+h-~o$JtvY;hMN(!q2T43li2^MI4>$MOAnR7PHQqSssw%(hlSvPlbzk zRZ<%XYu~45Kj%Y^?UXwH<(1D68<)$D9&>5K+c90&SS}q>h6#!o>;}mih4Ya@DO%)R z8PRzW@14dGH{=;CLRy)p-7k25TejS7HcA{7P!JWX99V;u1c?vNy-%JC=!h8# zhjoJS#yYc=Gb-J}zfDGM01{AhA%kV?H7=612MjC*Ln%*$Z75SA(?t6(myjTtXxNk? zSELfTC6D!rsWXAZdUFd`YZfHk2Bf1mZFi;^8o5xSo4#?*dFJ7swk#Y|XO@ zi4obtNOQg4p@LdgYJR+LxKT%gNAxI6qEm-IA=J0d^|BlFgeZ4uwKa&qcXa=!Mz@&? z6IF01^MR5FWnx2$^@fiiszcpD5l7mdDI?=#Q1b;^*L^dBQ!ma3Q{2B!!aJ*O!rEHx z9S=4@R@rEoW^!w8@h2$&gT^1-!0KC=fM*4)MnLta0M4d>m+nx(?H5C6R2fRZBt;#u zC>))k0Kf0!9Qr741$)63CG888b4)E)lP4Gcb7Md`ijm<0eCmX!DOd&sN+G+2X;^2v zi~@T&SGw3E@yVLUQ<(~yCcjfY3>@zS*RW`3giAl6J4oELDD`U-Mo@?4LMNHEP)oVH znC0un`hr1(aDHL3U6n${GJjAXoPXZJM0 z>G_-3_`%}}2Dm?HAP2lQ)T6VSYLji-YQ-@hn}qUr|>(&A&4*zg3TgN zYi7>0eTMPJN3k zlI44tI>M0|o?>DBAOw>XQg{mrK(Gz=tIV3>W;?BS%WWSs31P?ozh%4FG&y^NRkGA! zq&wN|&g;2&OZ(LB2!KmLydkaLC$maoEwevv2kmWdlnSn5gER^P(dFhIiU5( zLD+Nx0hzv@lqm##{6!V$SGXcpV5WR+zTqXIQRD+xP$YN4_;Fe93>D-CBbq_q1IoC9 z?dB!n(vWfLSH*8G+n@}36XZ2zfLTgTmj=4fFeK~c+wl(HY#z+o$H89c@(58QyiF)i z-g|5=+kn0u4-&5fGC(F(2;R|8>qN@TK4>Gv**!;u@=kU6` zXIMMUMXDsh6XTe6uACQW2sF5f%4Qsr9aB&~T@I!bj3Q`rC+0TEv5UTzBj zjke3ynyV0f1`(&G?vUwVO|Vk8Ro&0Dk^5wt>u{wa)I|!)OvWso_J$G$QCL(m`j=oY zW7MEhS!12LDF(-HHf^d{#J#)9uZC`!5LMViDW%AEgjjkdj}vl2PUXOR=Z`ce zR%1G@ZqlbW)(^{n#^nF}loh%%^dEVwz^|V}$KlJ%vxI8S8A~g?X#q$uifg1P6hMgy zE3xc7I%p@uh2V@G3Pr-8qWfOV3WEfECZO(qy@$^kGtJP)mQM;xQpMKd9YyEeDW)XN<>NdYe6vqSd#Zw$mk8a+gMMX^PwSvxuTX?=+W4 z8O3%DnRFxBKJh87l(RL6XDD$XBvR?~T~TZCO$4^_+Q>p7P?RbmO@WAH3K|g#b%bmM ztv#x(3s^7HmPk?X&L;p>HI)W_58K`8&uN!sP{^4IWC4;2Y~AXGYy89`;!C@og#3*YR_^fV z1j8rcCY7Yt9)KMl(%NO*Zj7M44>7cJDn{t2QwoTXqCA}3ZAixHGcO5LJqF7KYaHNr ziwt;`@M2L_o>`FOjd2K|dI39-X@O5;)g&R*e6X3DJ1eZK38Qp0+mwF7@B0z$^3Vk z^I$?m`^iinqvfz+`5-5S8Esm?XG+QWYf&9Sp=S+@NvFUxh#A`WD20b-7}s(1 zn^QCfgvX|Geh$KXZi}*oFhoe}?V{5}HAvZIL8Q#s47eti(&3}-VBXj&G3y|EFnq`g z%GbC|Cw7l={%iI*#p>-!cw)6J-FtBwu9%Vs?&^tD=~P6kiBcI5%+$|1*(~V{eYmIpT-!-0uKIK)Sz1 zMRMOD74Se)zuO;NMVM+r`&AcSrWeqjg@Fc?6wbYL`+VbhkLEw-=R&Hu;A$*8#?-Q$ zDvVgHC^7?i!E-A!QWd#m>}>a+KPKZVc}&Iawt8V2Qf5L~-te5SSP9zdL{+SDa*+pg z$#afQexC3}LP{S#tL@J$)KeIOpuKD6rk>}NX!z@Hka@6C6BJ;IFPsOQE3>+PdioxY zRe=Vtdd{U_6nNuaq;6+kl$pNEn%;QRPPUpyZuMnz_7wa_^1%%=h$h`XbfY>IqJ-V4 zhBR-m2yVrV{4EItE&v?WmWZ9?OR;uBX;Ep-n^CkG`D&vxkrPe;U`WAvd`taUB_rB~ zNEjb&tDZICg0aJO%gm5ug+qEJI+6c>;&l(2-7Iffw-F-*kSU#Xy3;a%>Q{W#0X-!& zF08On9(_cSjzD*<$eM&Ceh+XLY(Pl8`*fO2W0P&&<$Xt%O zca!RgvBd6P%0r*#P6((k>e~U`g@>>)5(Q0nDKRfCNFzH4 za-!H*q%v3BGzA)D4$H?jaZo5iQKUjtMY?%XkN{$ z6Bnx;7hr;|*$N;UaC9H`7D$MMBdzjTPN;7xDvUKeUD(HJ}7zzvHCa&r}n=jw)*iB$5f)`~R; z?d`60fgvi)1#r@uMgqtY^o5Yk_8OS*yCaY*tW=CV%}c{cshx;Qw=TE>LSr7|F}Q3D1DC?8^Rw&DqB`HtD{=h{loSjVK@*u7jd}SVjlNGcGf|vs{(PWkz3vNOONG zoV(mO5lV~MJip9o#k8=DE>LN9+X1qNR1_fd;4OM~k13{=Od@ zIch9T)y>6rN9{K^mPrpT%RU^S9+?ct$3Vm*y${x;>HKNmy2W4fr%}TCx41(j11^ON z4-o2Fe2SMr17b!O;NBY-oP#G3Faru|eACl*Mpr<%FSsQVR65!8*pY$aWhJaL?z{$* zr1>|PU|vWX4`UOH#vldvwBj`(MDQjM`-FY(x&Dhm2m*Oztd_-BhFR2Ne13BgdAOd4v?(ecFb_43l~@ukxYkdW8O?_|2FKiwwam zy$&L8iLmgv5E-l#)|c)2B6b(;_cGFeUu*ZbQzt>BZHT6Rkbj4?l=vIEig*+b=Yr<+ zVWl(QsCYv_glaq*`{K0cpTehAG!Sdbj-+*}#0Bq;#$*WG<`%SRLuPVllKTEU9|)?I zzd_k$`2n2*>kCbqNBWkdP5lg3<9sU(gZp({l4$%)Pf z<2x8Evt%n1Jhy9}JK@=%(|!8#-Mqj9@CT7Oob=D=oZH1#l0h0%D5#7CL|$nRx6j-X z!;{LrM*^gol~^U#yamlhw5H$@t2Q-G>GZCu_s5jwW7|@6zWtEzkZ9pvPJ`)J=RA#R zc$-5os`!zz0B`9{FWqLt#t~g*m9D!%Hq_}Bi9%slR?E>KrG>5zwlXgVIWD+@EFM@W z*K%dP!@pcDUYYTm)V!Qm$u{O7??F?h)fMi6rv6J%KvgDo&u2~P#G00O7D1RTYKy*9 zuZ>lK{1Tb8T*&hV01;Ki7=zG>Y$^WQ z^x5xFgL#EVOZv5j>!&e_XxdfZN_BFg%)!Yy$W7OWVeV_yD86Nuw9mD}?WS~}f1sp~ z^>5sWV46YU*|DfptkQg&G409-9vK-hXx*ODNur$k37eR78PM@B$@5u`a4l6yA{)DR zx5`VH##E3DP07Fx1ElYFgHPY1wy0Ol5CwJ*X@r+^YH-_GN~Igmj8Xn^-XzR}3Z*L% z)HlmlinP{;-dSF_rG(z_$5iQws5MNg7O!Z5JD6s2k}5NI8W-K*9gk(|bgGMt`X`!p zYekE$-by_yVsr?luJY_@Tyn3AasDa)oJr!NZ3DVvJys0F?QMbxeh0_4+C4w4)OsSGj z2H~NgZQ_65Xykn>(dIX2mEtYeNpME03MJ_|PYA*|ldt3h{*>$nY7>d4b$T*vBzkm{ z-`ly<7Uv(7zHN5f2cjDSL% z1aPj}tkwNlG3NH5**?SqgUoK@Pp}{|zB3@Py~@!d>V%a=ojLCGRw7R{84{;K$*O4e z^KI01>JryQ9V+_RN)scyLt0A_ZIim!4w>SY0JRl^e1xgIQ?E!t3)H?uOVBPo{>~tz z^R?Sp=MliOYRV9C1zmCB_c zTnVB0vIbr4#qiT3!PE5!*Dvofd{!b?`omVMi zn^XKBbw*zRPF*CO)b#&03K6FH92y^VY}#%nh3QvMZSKKeA0KyS0gT3#cuK1 z9oMV#af}YjcT=UVZn$4Pc`JIu-tKJ5MybipwY@Ita!ieahsLmyiY|S!Qjt6_c6}&X zk=wG{tiP!JTGT(0#yI1-w?I7q^gcZ`sB3btDwq>PKlvR0;{3_Fumdh@tpom)Nc(gT z7m$MrbwzxxA2Y@4vGr>hc}FT17m0=FLG!RROCvO(x?Meys&)6B{1l$zd@n=ZKQEe> zvQgj>G(%GW7;{YL%vY}@6I1C&=r%MLmc_-^b9>oZn-{SyQWsJvyU43jYJQwOKyNC3 zF2=OomUBxzwUGsd6b6OMUeb`qxXHcd1kze^qDhlC6?o8N9>fwFTnH0$?iI=0MFJ0! zR$8@GNg9c>)3D18?*nUrXV75CInAJluYmZue|LsfD256v>eGv8BIRxlH9p}4J;~q= zA~?G9%xLNZJgG6(Kh}aemT>1y1k{DtG;H>xyOaqGf)%WQTZoJRZ}9%us~wp%05ZSp zRYhx_{tmg#zhLkF;6lm&0{_qO|2&+}bBpgIqkFHbG@FT{qxJtkh|Sy&)HSFybE%t# zHAXx!V~i*genY=m^vK6@u!>vp8Ykk|GN10a5Ei12t&tvXF!%cZ2=L<06jK%${-rRt zOFz5{gUAeIbR_X#%t%$<4PurIBT>o;eTSmCZFe)C${JK z(3z;;pRjVyQ9e41>f673dtZ^c{ojA~ul|IzPdDZR(`F)rI(JA}2hCvK^#k6k3(<_i zij8E-r@lGcSW`zy3=mC`7Hp^yAuIk(^C83Rn-*ceS^>3nn@b$W$I6~jihiFe=%2HZ z5M~4_)JU$-Rj_m)?KoJc*sabtI5?eKjEMt7+5vT7!l}Oz=hz>Bbvo^y91+dzMaV^b zYpA%Bp~>PXE?qQSO_niF7RI1sz&^ykJeO4sqb4fEWf=s1%1wOq0q=?H_bwv$o3jSZ zVZ#gqSz^YE`k3KyJ{zuB9b1|kIyIg`+xsS55M?JCV>>IhrM2E)ha>@oY0ZYc$2Rx}-oBccYm>uV!%P1!Dk6Qsz4-JMT~N@*-nE(L1! zaOTh=GSTQK7Ov(6)qWR`!g(Za&ZX%0u~Zrmzci$Ej$>5VuI!yc^wsF9uInfh=LYOl z{EJ%0nE3mt5V>hwhw&u#7;PB3lF|RFKr*I~0>>p8$8WiufKo}k%?a-R@=xUDf15db zOB>ktR%K!aaGdg#+8WKf2}#2LKs`g7vW<#LeH<)>8#!HmjvmCY)UB76{`*ELo|NNZTiZ!qjHx#(^^VaUuLDtpOj*Z(a?oS{n`XZJM-Ia!H6G)=(Hd zBFDw?)k?{#OZ#G2y$;q*<+IhK04Q@k6cF_>9q%tEsmE9qPNWGh9<&48zpsq zI=|+pJUIq*`CYKgR9l$UALg+PrkSzuX36y%biH4y?_h``HZbwEEZDDlSDDZCP8Lt} z*rF3Ijswpoh>ar*6!Q^Eocln-`4O7I|CD_*c8TL*r~Tezg>o`O6f86Q<7k$tAHDU2 zrO9Lyon4gSL1R|r?oQB;Ws1QUw|3-Y6GxA*Ec;HUi|=oS=a%gUN}ygFW@828lPKD6 zi1|&9m!!OoFFhJ*YBubKW7A3JRCD_0ccggf*Dl`<2bH2$4)O_UeG@g{E$bTJPsTuWIfLSs~CS=Z57zmu-h~L7?a(A)LyqJ>N=9zQ* zJp`>may^+AkY$|dbVs-U;Njqb;%n~{(7KxA_&m}0j$Jy{$KgW@ULur4yeMC@wb0=P z2XmlBxS+(D+3OjIkps&jv>tW08Y?sjY&Q!j-`2FhbHJzeb^zuEIb{iDPxpQUqz| zOa&-|YqMxW$(C;x8=6p6nfY(9s5>L1ryHILZ5}8C())JB3pcYZA)LL;wo#-`2X+^ReoTq7(rIP zsHiLF*+HmBMU+95Dc=Ks$wTL@N4T}Hs177~eUqv0Z)}~42wT-YeTl*izz<>RhN4Ew ziqS?xzw{HI5(|EC!qobbjU&o$GN}2+)TN;&%Ns5k0J0RXKTs92CT03IeJS*R;#nun zJmk5K6`MWt!W;Mhr-DQ@728d5S^~wKCE2EED9WoD^%dDNjoXEb8CMtJeu#8HfaN>m3Lq{?9b(h*d4HaZhVUK?;Tq;a90wky` zySogk1Pu^S9(aT>6=ObekfPkrj1+0h(MveuEaB))dMNSeJJXEi-L!P;pXe<>O*i6K zDzRfLM(l&=MF+)hdv93K@3*BjM+h?lj}T1J5QRbn%IMWqmRCv|Q)l9%j$`v}hQB7)l1yP(8GC!MHup}4=Ct5wL&ZNMvgL4z*Ue}lM1 z2D+d$vm;|Fl457dd`zC&Y}dgPc^ODZPpYnrGlqX7a>PZw^+xG%UBb34E`UMRTxoA9 z?-&__≥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 gK@1WdzW4 { + if (item.name != 'csrfmiddlewaretoken') { + obj[item.name] = item.value; + } + }); + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); + $.ajax({ url: form.attr("action"), - data: form.serialize(), - type: form.attr("method"), + data: JSON.stringify(obj), + type: 'PATCH', dataType: 'json', success: function (data) { - if (data.form_is_valid) { - $("#modal-update").modal('hide'); - var d = table.row(row).data(); - d[0] = ``; - d[1] = data.data.name; - d[4] = data.data.query; - table.row(row).data(d).draw(); - $.toast({ - title: 'Bookmark status!', - content: 'Bookmark updated.', - type: 'success', - delay: 5000 - }); - } else { - $("#modal-update .modal-content").html(data.html_form); - $.toast({ - title: 'Bookmark status!', - content: 'Error during submission.', - type: 'error', - delay: 5000 - }); - } + var d = table.row(row).data(); + d[0] = ``; + d[1] = data.name; + d[4] = data.query; + table.row(row).data(d).draw(); + $.toast({ + title: 'Bookmark status!', + content: 'Bookmark updated.', + type: 'success', + delay: 5000 + }); + $("#modal-update").modal('hide'); + }, + error: function () { + $.toast({ + title: 'Bookmark status!', + content: 'Error during submission.', + type: 'error', + delay: 5000 + }); + $("#modal-update").modal('hide'); } }); }); diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index c2d5cd1e..6e7e0e0a 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -116,7 +116,7 @@

    History Log
    }); // ADD BOOKMARK FORM SUBMIT - $(document).on("submit", "#add-bookmark", function (e) { + $(document).on("submit", "#create-bookmark", function (e) { e.preventDefault(); var form = $(this); @@ -124,29 +124,41 @@
    History Log
    $("#id_selected_plugin").val(selected_plugin); $("#id_query").val($("#example_filter input").val()); + let formData = form.serializeArray(); + let obj = {}; + formData.forEach(item=>{ + if(item.name != 'csrfmiddlewaretoken'){ + obj[item.name] = item.value; + } + }); + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); + $.ajax({ url: form.attr("action"), - data: form.serialize(), + data: JSON.stringify(obj), + contentType: "application/json", type: form.attr("method"), dataType: 'json', success: function (data) { - if (data.form_is_valid) { - $("#modal-update").modal('hide'); - $.toast({ - title: 'Bookmark saved!', - content: 'Bookmark saved.', - type: 'success', - delay: 5000 - }); - } else { - $("#modal-update").modal('hide'); - $.toast({ - title: 'Bookmark status!', - content: 'Error during submission.', - type: 'error', - delay: 5000 - }); - } + + $.toast({ + title: 'Bookmark saved!', + content: 'Bookmark saved.', + type: 'success', + delay: 5000 + }); + $("#modal-update").modal('hide'); + }, + error: function () { + $.toast({ + title: 'Bookmark status!', + content: 'Error during submission.', + type: 'error', + delay: 5000 + }); + $("#modal-update").modal('hide'); } }); }); diff --git a/orochi/templates/website/partial_bookmark_create.html b/orochi/templates/website/partial_bookmark_create.html index 32ccd3cb..a8d7a9b5 100644 --- a/orochi/templates/website/partial_bookmark_create.html +++ b/orochi/templates/website/partial_bookmark_create.html @@ -1,7 +1,7 @@ {% load widget_tweaks %} {% load custom_tags %} -
    + {{ form.media }} {% csrf_token %} -
    \ No newline at end of file + diff --git a/orochi/templates/website/partial_bookmark_edit.html b/orochi/templates/website/partial_bookmark_edit.html index c97d2a44..3cb6ccaa 100644 --- a/orochi/templates/website/partial_bookmark_edit.html +++ b/orochi/templates/website/partial_bookmark_edit.html @@ -1,6 +1,6 @@ {% load widget_tweaks %} -
    + {{ form.media }} {% csrf_token %} -
    \ No newline at end of file + diff --git a/orochi/website/defaults.py b/orochi/website/defaults.py index d6b6b6ea..54f9fc8b 100644 --- a/orochi/website/defaults.py +++ b/orochi/website/defaults.py @@ -66,105 +66,114 @@ class OSEnum(models.TextChoices): (RESULT_STATUS_ERROR, "Error"), (RESULT_STATUS_DISABLED, "Disabled"), ) -ICONS = ( - ("ss-arn", "Arabian Nights"), - ("ss-atq", "Antiquities"), - ("ss-leg", "Legends"), - ("ss-drk", "The Dark"), - ("ss-fem", "Fallen Empires"), - ("ss-hml", "Homelands"), - ("ss-ice", "Ice Age"), - ("ss-ice2", "Ice Age (Original)"), - ("ss-all", "Alliances"), - ("ss-csp", "Coldsnap"), - ("ss-mir", "Mirage"), - ("ss-vis", "Visions"), - ("ss-wth", "Weatherlight"), - ("ss-tmp", "Tempest"), - ("ss-sth", "Stronghold"), - ("ss-exo", "Exodus"), - ("ss-usg", "Urza's Saga"), - ("ss-ulg", "Urza's Legacy"), - ("ss-uds", "Urza's Destiny"), - ("ss-mmq", "Mercadian Masques"), - ("ss-nem", "Nemesis"), - ("ss-pcy", "Prophecy"), - ("ss-inv", "Invasion"), - ("ss-pls", "Planeshift"), - ("ss-apc", "Apocalypse"), - ("ss-ody", "Odyssey"), - ("ss-tor", "Torment"), - ("ss-jud", "Judgement"), - ("ss-ons", "Onslaught"), - ("ss-lgn", "Legions"), - ("ss-scg", "Scourge"), - ("ss-mrd", "Mirrodin"), - ("ss-dst", "Darksteel"), - ("ss-5dn", "Fifth Dawn"), - ("ss-chk", "Champions of Kamigawa"), - ("ss-bok", "Betrayers of Kamigawa"), - ("ss-sok", "Saviors of Kamigawa"), - ("ss-rav", "Ravnica"), - ("ss-gpt", "Guildpact"), - ("ss-dis", "Dissension"), - ("ss-tsp", "Time Spiral"), - ("ss-plc", "Planar Chaos"), - ("ss-fut", "Future Sight"), - ("ss-lrw", "Lorwyn"), - ("ss-mor", "Morningtide"), - ("ss-shm", "Shadowmoor"), - ("ss-eve", "Eventide"), - ("ss-ala", "Shards of Alara"), - ("ss-con", "Conflux"), - ("ss-arb", "Alara Reborn"), - ("ss-zen", "Zendikar"), - ("ss-wwk", "Worldwake"), - ("ss-roe", "Rise of the Eldrazi"), - ("ss-som", "Scars of Mirrodin"), - ("ss-mbs", "Mirrodin Besieged"), - ("ss-nph", "New Phyrexia"), - ("ss-isd", "Innistrad"), - ("ss-dka", "Dark Ascension"), - ("ss-avr", "Avacyn Restored"), - ("ss-rtr", "Return to Ravnica"), - ("ss-gtc", "Gatecrash"), - ("ss-dgm", "Dragon's Maze"), - ("ss-ths", "Theros"), - ("ss-bng", "Born of the Gods"), - ("ss-jou", "Journey into Nyx"), - ("ss-ktk", "Khans of Tarkir"), - ("ss-frf", "Fate Reforged"), - ("ss-dtk", "Dragons of Tarkir"), - ("ss-bfz", "Battle for Zendikar"), - ("ss-ogw", "Oath of the Gatewatch"), - ("ss-soi", "Shadows Over Innistrad"), - ("ss-emn", "Eldritch Moon"), - ("ss-kld", "Kaladesh"), - ("ss-aer", "Aether Revolt"), - ("ss-akh", "Amonkhet"), - ("ss-hou", "Hour of Devastation"), - ("ss-xln", "Ixalan"), - ("ss-rix", "Rivals of Ixalan"), - ("ss-dom", "Dominaria"), - ("ss-grn", "Guilds of Ravnica"), - ("ss-rna", "Ravnica Allegiance"), - ("ss-war", "War of the Spark"), - ("ss-eld", "Throne of Eldraine"), - ("ss-thb", "Theros: Beyond Death"), - ("ss-iko", "koria: Lair of Behemoths"), - ("ss-znr", "Zendikar Rising"), - ("ss-khm", "Kaldheim"), - ("ss-stx", "Strixhaven: School of Mages"), - ("ss-mid", "Innistrad: Midnight Hunt"), - ("ss-vow", "Innistrad: Crimson Vow"), - ("ss-neo", "Kamigawa: Neon Dynasty"), - ("ss-snc", "Streets of New Capenna"), - ("ss-dmu", "Dominaria United"), - ("ss-bro", "The Brothers' War"), - ("ss-one", "Phyrexia: All Will Be One"), - ("ss-mom", "March of the Machine"), - ("ss-mat", "March of the Machine: The Aftermath"), - ("ss-woe", "Wilds of Eldraine"), -) + + +class IconEnum(models.TextChoices): + SS_ORI = "ss-ori", "Magic Origins" + SS_AFR = "ss-afr", "Adventures in the Forgotten Realms" + SS_ARN = "ss-arn", "Arabian Nights" + SS_ATQ = "ss-atq", "Antiquities" + SS_LEG = "ss-leg", "Legends" + SS_DRK = "ss-drk", "The Dark" + SS_FEM = "ss-fem", "Fallen Empires" + SS_HML = "ss-hml", "Homelands" + SS_ICE = "ss-ice", "Ice Age" + SS_ICE2 = "ss-ice2", "Ice Age (Original)" + SS_ALL = "ss-all", "Alliances" + SS_CSP = "ss-csp", "Coldsnap" + SS_MIR = "ss-mir", "Mirage" + SS_VIS = "ss-vis", "Visions" + SS_WTH = "ss-wth", "Weatherlight" + SS_TMP = "ss-tmp", "Tempest" + SS_STH = "ss-sth", "Stronghold" + SS_EXO = "ss-exo", "Exodus" + SS_USG = "ss-usg", "Urza's Saga" + SS_ULG = "ss-ulg", "Urza's Legacy" + SS_UDS = "ss-uds", "Urza's Destiny" + SS_MMQ = "ss-mmq", "Mercadian Masques" + SS_NEM = "ss-nem", "Nemesis" + SS_PCY = "ss-pcy", "Prophecy" + SS_INV = "ss-inv", "Invasion" + SS_PLS = "ss-pls", "Planeshift" + SS_APC = "ss-apc", "Apocalypse" + SS_ODY = "ss-ody", "Odyssey" + SS_TOR = "ss-tor", "Torment" + SS_JUD = "ss-jud", "Judgement" + SS_ONS = "ss-ons", "Onslaught" + SS_LGN = "ss-lgn", "Legions" + SS_SCG = "ss-scg", "Scourge" + SS_MRD = "ss-mrd", "Mirrodin" + SS_DST = "ss-dst", "Darksteel" + SS_5DN = "ss-5dn", "Fifth Dawn" + SS_CHK = "ss-chk", "Champions of Kamigawa" + SS_BOK = "ss-bok", "Betrayers of Kamigawa" + SS_SOK = "ss-sok", "Saviors of Kamigawa" + SS_RAV = "ss-rav", "Ravnica" + SS_GPT = "ss-gpt", "Guildpact" + SS_DIS = "ss-dis", "Dissension" + SS_TSP = "ss-tsp", "Time Spiral" + SS_PLC = "ss-plc", "Planar Chaos" + SS_FUT = "ss-fut", "Future Sight" + SS_LRW = "ss-lrw", "Lorwyn" + SS_MOR = "ss-mor", "Morningtide" + SS_SHM = "ss-shm", "Shadowmoor" + SS_EVE = "ss-eve", "Eventide" + SS_ALA = "ss-ala", "Shards of Alara" + SS_CON = "ss-con", "Conflux" + SS_ARB = "ss-arb", "Alara Reborn" + SS_ZEN = "ss-zen", "Zendikar" + SS_WWK = "ss-wwk", "Worldwake" + SS_ROE = "ss-roe", "Rise of the Eldrazi" + SS_SOM = "ss-som", "Scars of Mirrodin" + SS_MBS = "ss-mbs", "Mirrodin Besieged" + SS_NPH = "ss-nph", "New Phyrexia" + SS_ISD = "ss-isd", "Innistrad" + SS_DKA = "ss-dka", "Dark Ascension" + SS_AVR = "ss-avr", "Avacyn Restored" + SS_RTR = "ss-rtr", "Return to Ravnica" + SS_GTC = "ss-gtc", "Gatecrash" + SS_DGM = "ss-dgm", "Dragon's Maze" + SS_THS = "ss-ths", "Theros" + SS_BNG = "ss-bng", "Born of the Gods" + SS_JOU = "ss-jou", "Journey into Nyx" + SS_KTK = "ss-ktk", "Khans of Tarkir" + SS_FRF = "ss-frf", "Fate Reforged" + SS_DTK = "ss-dtk", "Dragons of Tarkir" + SS_BFZ = "ss-bfz", "Battle for Zendikar" + SS_OGW = "ss-ogw", "Oath of the Gatewatch" + SS_SOI = "ss-soi", "Shadows Over Innistrad" + SS_EMN = "ss-emn", "Eldritch Moon" + SS_KLD = "ss-kld", "Kaladesh" + SS_AER = "ss-aer", "Aether Revolt" + SS_AKH = "ss-akh", "Amonkhet" + SS_HOU = "ss-hou", "Hour of Devastation" + SS_XLN = "ss-xln", "Ixalan" + SS_RIX = "ss-rix", "Rivals of Ixalan" + SS_DOM = "ss-dom", "Dominaria" + SS_GRN = "ss-grn", "Guilds of Ravnica" + SS_RNA = "ss-rna", "Ravnica Allegiance" + SS_WAR = "ss-war", "War of the Spark" + SS_ELD = "ss-eld", "Throne of Eldraine" + SS_THB = "ss-thb", "Theros: Beyond Death" + SS_IKO = "ss-iko", "koria: Lair of Behemoths" + SS_ZNR = "ss-znr", "Zendikar Rising" + SS_KHM = "ss-khm", "Kaldheim" + SS_STX = "ss-stx", "Strixhaven: School of Mages" + SS_MID = "ss-mid", "Innistrad: Midnight Hunt" + SS_VOW = "ss-vow", "Innistrad: Crimson Vow" + SS_NEO = "ss-neo", "Kamigawa: Neon Dynasty" + SS_SNC = "ss-snc", "Streets of New Capenna" + SS_DMU = "ss-dmu", "Dominaria United" + SS_BRO = "ss-bro", "The Brothers' War" + SS_ONE = "ss-one", "Phyrexia: All Will Be One" + SS_MOM = "ss-mom", "March of the Machine" + SS_MAT = "ss-mat", "March of the Machine: The Aftermath" + SS_WOE = "ss-woe", "Wilds of Eldraine" + SS_LCI = "ss-lci", "Lost Caverns of Ixalan" + SS_MKM = "ss-mkm", "Murders at Karlov Manor" + SS_OTJ = "ss-otj", "Outlaws of Thunder Junction" + SS_BIG = "ss-big", "The Big Score" + SS_BLB = "ss-blb", "Bloomburrow" + DEFAULT_YARA_PATH = "/yara/default.yara" diff --git a/orochi/website/forms.py b/orochi/website/forms.py index a248575f..3d257156 100644 --- a/orochi/website/forms.py +++ b/orochi/website/forms.py @@ -53,7 +53,6 @@ class Meta: class EditBookmarkForm(forms.ModelForm): - selected_bookmark = forms.CharField(widget=forms.HiddenInput()) class Meta: model = Bookmark diff --git a/orochi/website/migrations/0056_alter_bookmark_icon.py b/orochi/website/migrations/0056_alter_bookmark_icon.py new file mode 100644 index 00000000..740e22d8 --- /dev/null +++ b/orochi/website/migrations/0056_alter_bookmark_icon.py @@ -0,0 +1,128 @@ +# Generated by Django 5.0.4 on 2024-04-16 16:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("website", "0055_alter_dump_status"), + ] + + operations = [ + migrations.AlterField( + model_name="bookmark", + name="icon", + field=models.CharField( + choices=[ + ("ss-ori", "Magic Origins"), + ("ss-afr", "Adventures in the Forgotten Realms"), + ("ss-arn", "Arabian Nights"), + ("ss-atq", "Antiquities"), + ("ss-leg", "Legends"), + ("ss-drk", "The Dark"), + ("ss-fem", "Fallen Empires"), + ("ss-hml", "Homelands"), + ("ss-ice", "Ice Age"), + ("ss-ice2", "Ice Age (Original)"), + ("ss-all", "Alliances"), + ("ss-csp", "Coldsnap"), + ("ss-mir", "Mirage"), + ("ss-vis", "Visions"), + ("ss-wth", "Weatherlight"), + ("ss-tmp", "Tempest"), + ("ss-sth", "Stronghold"), + ("ss-exo", "Exodus"), + ("ss-usg", "Urza's Saga"), + ("ss-ulg", "Urza's Legacy"), + ("ss-uds", "Urza's Destiny"), + ("ss-mmq", "Mercadian Masques"), + ("ss-nem", "Nemesis"), + ("ss-pcy", "Prophecy"), + ("ss-inv", "Invasion"), + ("ss-pls", "Planeshift"), + ("ss-apc", "Apocalypse"), + ("ss-ody", "Odyssey"), + ("ss-tor", "Torment"), + ("ss-jud", "Judgement"), + ("ss-ons", "Onslaught"), + ("ss-lgn", "Legions"), + ("ss-scg", "Scourge"), + ("ss-mrd", "Mirrodin"), + ("ss-dst", "Darksteel"), + ("ss-5dn", "Fifth Dawn"), + ("ss-chk", "Champions of Kamigawa"), + ("ss-bok", "Betrayers of Kamigawa"), + ("ss-sok", "Saviors of Kamigawa"), + ("ss-rav", "Ravnica"), + ("ss-gpt", "Guildpact"), + ("ss-dis", "Dissension"), + ("ss-tsp", "Time Spiral"), + ("ss-plc", "Planar Chaos"), + ("ss-fut", "Future Sight"), + ("ss-lrw", "Lorwyn"), + ("ss-mor", "Morningtide"), + ("ss-shm", "Shadowmoor"), + ("ss-eve", "Eventide"), + ("ss-ala", "Shards of Alara"), + ("ss-con", "Conflux"), + ("ss-arb", "Alara Reborn"), + ("ss-zen", "Zendikar"), + ("ss-wwk", "Worldwake"), + ("ss-roe", "Rise of the Eldrazi"), + ("ss-som", "Scars of Mirrodin"), + ("ss-mbs", "Mirrodin Besieged"), + ("ss-nph", "New Phyrexia"), + ("ss-isd", "Innistrad"), + ("ss-dka", "Dark Ascension"), + ("ss-avr", "Avacyn Restored"), + ("ss-rtr", "Return to Ravnica"), + ("ss-gtc", "Gatecrash"), + ("ss-dgm", "Dragon's Maze"), + ("ss-ths", "Theros"), + ("ss-bng", "Born of the Gods"), + ("ss-jou", "Journey into Nyx"), + ("ss-ktk", "Khans of Tarkir"), + ("ss-frf", "Fate Reforged"), + ("ss-dtk", "Dragons of Tarkir"), + ("ss-bfz", "Battle for Zendikar"), + ("ss-ogw", "Oath of the Gatewatch"), + ("ss-soi", "Shadows Over Innistrad"), + ("ss-emn", "Eldritch Moon"), + ("ss-kld", "Kaladesh"), + ("ss-aer", "Aether Revolt"), + ("ss-akh", "Amonkhet"), + ("ss-hou", "Hour of Devastation"), + ("ss-xln", "Ixalan"), + ("ss-rix", "Rivals of Ixalan"), + ("ss-dom", "Dominaria"), + ("ss-grn", "Guilds of Ravnica"), + ("ss-rna", "Ravnica Allegiance"), + ("ss-war", "War of the Spark"), + ("ss-eld", "Throne of Eldraine"), + ("ss-thb", "Theros: Beyond Death"), + ("ss-iko", "koria: Lair of Behemoths"), + ("ss-znr", "Zendikar Rising"), + ("ss-khm", "Kaldheim"), + ("ss-stx", "Strixhaven: School of Mages"), + ("ss-mid", "Innistrad: Midnight Hunt"), + ("ss-vow", "Innistrad: Crimson Vow"), + ("ss-neo", "Kamigawa: Neon Dynasty"), + ("ss-snc", "Streets of New Capenna"), + ("ss-dmu", "Dominaria United"), + ("ss-bro", "The Brothers' War"), + ("ss-one", "Phyrexia: All Will Be One"), + ("ss-mom", "March of the Machine"), + ("ss-mat", "March of the Machine: The Aftermath"), + ("ss-woe", "Wilds of Eldraine"), + ("ss-lci", "Lost Caverns of Ixalan"), + ("ss-mkm", "Murders at Karlov Manor"), + ("ss-otj", "Outlaws of Thunder Junction"), + ("ss-big", "The Big Score"), + ("ss-blb", "Bloomburrow"), + ], + default="ss-ori", + max_length=50, + ), + ), + ] diff --git a/orochi/website/models.py b/orochi/website/models.py index 27119692..ff2bb90a 100644 --- a/orochi/website/models.py +++ b/orochi/website/models.py @@ -14,7 +14,6 @@ from orochi.website.defaults import ( DEFAULT_YARA_PATH, - ICONS, RESULT, RESULT_STATUS_DISABLED, RESULT_STATUS_NOT_STARTED, @@ -22,6 +21,7 @@ STATUS, TOAST_DUMP_COLORS, TOAST_RESULT_COLORS, + IconEnum, OSEnum, ) from orochi.ya.models import Ruleset @@ -144,7 +144,9 @@ class Bookmark(models.Model): indexes = models.ManyToManyField(Dump) plugin = models.ForeignKey(Plugin, on_delete=models.CASCADE) name = models.CharField(max_length=250) - icon = models.CharField(choices=ICONS, default="ss-ori", max_length=50) + icon = models.CharField( + choices=IconEnum.choices, default=IconEnum.SS_ORI, max_length=50 + ) star = models.BooleanField(default=False) query = models.CharField(max_length=500, blank=True, null=True) diff --git a/orochi/website/views.py b/orochi/website/views.py index 71aa82b1..c64561c7 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -822,92 +822,30 @@ def export(request): # BOOKMARKS ############################## @login_required +@require_http_methods(["GET"]) def add_bookmark(request): """Add bookmark in user settings""" - data = {} - - if request.method == "POST": - updated_request = { - "name": request.POST.get("name"), - "query": request.POST.get("query"), - "star": request.POST.get("star"), - "icon": request.POST.get("icon"), - } - - id_indexes = request.POST.get("selected_indexes") - indexes = [] - for id_index in id_indexes.split(","): - index = get_object_or_404(Dump, index=id_index) - indexes.append(index) - - id_plugin = request.POST.get("selected_plugin") - plugin = get_object_or_404(Plugin, name=id_plugin) - - form = BookmarkForm(data=updated_request) - if form.is_valid(): - bookmark = form.save(commit=False) - bookmark.user = request.user - bookmark.plugin = plugin - bookmark.save() - for index in indexes: - bookmark.indexes.add(index) - data["form_is_valid"] = True - else: - data["form_is_valid"] = False - else: - form = BookmarkForm() - - context = {"form": form} - data["html_form"] = render_to_string( - "website/partial_bookmark_create.html", - context, - request=request, - ) + data = { + "html_form": render_to_string( + "website/partial_bookmark_create.html", + {"form": BookmarkForm()}, + request=request, + ) + } return JsonResponse(data) @login_required +@require_http_methods(["GET"]) def edit_bookmark(request): """Edit bookmark information""" - data = {} - bookmark = None - - if request.method == "POST": - bookmark = get_object_or_404( - Bookmark, name=request.POST.get("selected_bookmark"), user=request.user - ) - elif request.method == "GET": - bookmark = get_object_or_404( - Bookmark, pk=request.GET.get("pk"), user=request.user - ) - - if request.method == "POST": - form = EditBookmarkForm( - data=request.POST, - instance=bookmark, - ) - if form.is_valid(): - bookmark = form.save() - data["form_is_valid"] = True - data["data"] = { - "name": bookmark.name, - "icon": bookmark.icon, - "query": bookmark.query, - } - else: - data["form_is_valid"] = False - else: - form = EditBookmarkForm( - instance=bookmark, - initial={"selected_bookmark": bookmark.name}, + bookmark = get_object_or_404(Bookmark, pk=request.GET.get("pk"), user=request.user) + context = {"form": EditBookmarkForm(instance=bookmark), "id": bookmark.pk} + data = { + "html_form": render_to_string( + "website/partial_bookmark_edit.html", context, request=request ) - - context = {"form": form} - data["html_form"] = render_to_string( - "website/partial_bookmark_edit.html", - context, - request=request, - ) + } return JsonResponse(data) diff --git a/requirements/base.txt b/requirements/base.txt index cc56bad1..1cd7be5a 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,7 +7,7 @@ argon2-cffi==23.1.0 # https://github.com/evansd/whitenoise whitenoise==6.6.0 # https://github.com/andymccurdy/redis-py -redis==5.0.3 +redis==5.0.4 # https://github.com/redis/hiredis-py hiredis==2.3.2 # https://github.com/psycopg/psycopg2 @@ -20,21 +20,21 @@ python-magic==0.4.27 # Django # ------------------------------------------------------------------------------ # https://www.djangoproject.com/ -django==5.0.4 +django==5.0.6 # https://github.com/django/channels -channels[daphne]==4.0.0 +channels[daphne]==4.1.0 # https://github.com/django/channels_redis channels_redis==4.2.0 # https://github.com/joke2k/django-environ django-environ==0.11.2 # https://github.com/pennersr/django-allauth -django-allauth==0.61.1 +django-allauth==0.63.1 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==2.1 # https://github.com/jazzband/django-redis django-redis==5.4.0 # https://gunicorn.org/ -gunicorn==21.2.0 +gunicorn==22.0.0 # Django Ninja @@ -64,18 +64,18 @@ django-admin-multiple-choice-list-filter==0.1.1 # Elasticsearch # ------------------------------------------------------------------------------ # https://github.com/elastic/elasticsearch-py -elasticsearch==8.13.0 +elasticsearch==8.13.1 # https://github.com/elastic/elasticsearch-dsl-py -elasticsearch-dsl==8.13.0 +elasticsearch-dsl==8.13.1 # https://github.com/jurismarches/luqum luqum==0.13.0 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.4.1 +dask==2024.5.1 # https://github.com/dask/distributed -distributed==2024.4.1 +distributed==2024.5.1 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.0.8 # https://github.com/python-lz4/python-lz4 @@ -89,7 +89,7 @@ toolz==0.12.1 # https://pypi.org/project/tornado/ tornado==6.4 # https://pandas.pydata.org/ -pandas==2.2.1 +pandas==2.2.2 # Volatility # ------------------------------------------------------------------------------ @@ -100,13 +100,13 @@ pandas==2.2.1 # https://github.com/Viicos/clamdpy clamdpy==0.1.0.post1 # https://github.com/VirusTotal/vt-py -vt-py==0.18.0 +vt-py==0.18.2 # https://github.com/mkorman90/regipy/ -regipy[full]==4.1.1 +regipy[full]==4.2.1 # http://www.capstone-engine.org/ capstone==5.0.1 # https://github.com/Julian/jsonschema -jsonschema==4.21.1 +jsonschema==4.22.0 # https://github.com/Legrandin/pycryptodome pycryptodome==3.20.0 # https://github.com/maxmind/GeoIP2-python @@ -133,7 +133,7 @@ pefile==2023.2.7 # misp export # ------------------------------------------------------------------------------ # https://github.com/MISP/PyMISP -pymisp==2.4.188 +pymisp==2.4.190 # ldap # ------------------------------------------------------------------------------ diff --git a/requirements/local.txt b/requirements/local.txt index 6c84a993..e3a5c767 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -5,7 +5,7 @@ # https://github.com/python/mypy mypy==1.9.0 # https://github.com/typeddjango/django-stubs -django-stubs==4.2.7 +django-stubs==5.0.0 # https://github.com/pytest-dev/pytest pytest==8.1.1 # https://github.com/Frozenball/pytest-sugar @@ -18,13 +18,13 @@ flake8==7.0.0 # https://github.com/gforcada/flake8-isort flake8-isort==6.1.1 # https://github.com/nedbat/coveragepy -coverage==7.4.4 +coverage==7.5.1 # https://github.com/ambv/black -black==24.3.0 +black==24.4.2 # https://github.com/PyCQA/pylint-django pylint-django==2.5.5 # https://github.com/pre-commit/pre-commit -pre-commit==3.6.2 +pre-commit==3.7.1 # Django # ------------------------------------------------------------------------------ From 30e3535844d40ab18fa4a8f16462990ce1801db5 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 11 Jun 2024 15:44:47 +0200 Subject: [PATCH 53/84] #1073 wip --- compose/local/__init__.py | 2 +- compose/local/dask/Dockerfile | 4 +- compose/local/django/Dockerfile | 2 +- orochi/api/api.py | 2 + orochi/api/filters.py | 35 +++++ orochi/api/models.py | 19 +++ orochi/api/routers/rules.py | 153 +++++++++++++++++++++ orochi/templates/users/user_bookmarks.html | 4 +- orochi/templates/users/user_rules.html | 56 +++++++- orochi/ya/models.py | 7 +- orochi/ya/schema.py | 5 +- orochi/ya/urls.py | 3 +- orochi/ya/views.py | 101 +------------- requirements/base.txt | 19 +-- requirements/local.txt | 8 +- 15 files changed, 287 insertions(+), 133 deletions(-) create mode 100644 orochi/api/routers/rules.py diff --git a/compose/local/__init__.py b/compose/local/__init__.py index bd93e7bd..4e86eacf 100644 --- a/compose/local/__init__.py +++ b/compose/local/__init__.py @@ -45,7 +45,7 @@ # We use the SemVer 2.0.0 versioning scheme VERSION_MAJOR = 2 # Number of releases of the library with a breaking change VERSION_MINOR = 7 # Number of changes that only add to the interface -VERSION_PATCH = 0 # Number of changes that do not change the interface +VERSION_PATCH = 1 # Number of changes that do not change the interface VERSION_SUFFIX = "" # TODO: At version 2.0.0, remove the symbol_shift feature diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 102b2e51..0c4078aa 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.5.1-py3.12 +FROM daskdev/dask:2024.5.2-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -47,7 +47,7 @@ RUN python setup.py build \ # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.44 -e git+https://github.com/volatilityfoundation/volatility3.git@dc7a3878fa39156d89d567c3e823f1956675f192#egg=volatility3 \ +RUN pip install uv==0.2.10 -e git+https://github.com/volatilityfoundation/volatility3.git@543a39485bdf57df47d731b55ab112e04f3033f0#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 7aa05de3..b21fdd95 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -65,7 +65,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.1.44 -e git+https://github.com/volatilityfoundation/volatility3.git@dc7a3878fa39156d89d567c3e823f1956675f192#egg=volatility3 \ +RUN pip install uv==0.2.10 -e git+https://github.com/volatilityfoundation/volatility3.git@543a39485bdf57df47d731b55ab112e04f3033f0#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/orochi/api/api.py b/orochi/api/api.py index f008272a..2cafa4af 100644 --- a/orochi/api/api.py +++ b/orochi/api/api.py @@ -5,6 +5,7 @@ from orochi.api.routers.dumps import router as dumps_router from orochi.api.routers.folders import router as folders_router from orochi.api.routers.plugins import router as plugins_router +from orochi.api.routers.rules import router as rules_router from orochi.api.routers.users import router as users_router from orochi.api.routers.utils import router as utils_router @@ -16,3 +17,4 @@ api.add_router("/plugins/", plugins_router, tags=["Plugins"]) api.add_router("/utils/", utils_router, tags=["Utils"]) api.add_router("/bookmarks/", bookmarks_router, tags=["Bookmarks"]) +api.add_router("/rules/", rules_router, tags=["Rules"]) diff --git a/orochi/api/filters.py b/orochi/api/filters.py index 9dbadb37..f19878c9 100644 --- a/orochi/api/filters.py +++ b/orochi/api/filters.py @@ -1,6 +1,8 @@ from enum import Enum +from typing import List from ninja import Schema +from pydantic import root_validator class OPERATING_SYSTEM(str, Enum): @@ -16,3 +18,36 @@ class OperatingSytemFilters(Schema): class DumpFilters(Schema): result: int = None + + +################################################### +# Rules +################################################### +class Search(Schema): + value: str = None + regex: bool = False + + +class Column(Schema): + data: int + name: str = None + searchable: bool = True + orderable: bool = True + search: Search = None + + +class Order(Schema): + column: int = 0 + dir: str = "asc" + + +class RulesFilter(Schema): + start: int = 0 + length: int = 10 + columns: List[Column] = [] + search: Search = None + order: List[Order] = [] + + @root_validator(pre=True) + def extract_data(cls, v): + return v diff --git a/orochi/api/models.py b/orochi/api/models.py index a87d2fed..9fa310e5 100644 --- a/orochi/api/models.py +++ b/orochi/api/models.py @@ -7,6 +7,7 @@ from orochi.website.defaults import OSEnum from orochi.website.models import Bookmark, Dump, Folder, Plugin +from orochi.ya.models import Rule ################################################### # Auth @@ -233,3 +234,21 @@ class BookmarksInSchema(Schema): icon: str = None selected_plugin: str = None query: Optional[str] = None + + +################################################### +# Rules +################################################### +class RuleBuildSchema(Schema): + rule_ids: List[int] + rulename: str + + +class RulesOutSchema(ModelSchema): + class Meta: + model = Rule + fields = ["id", "path", "enabled", "compiled", "ruleset", "created", "updated"] + + +class ListStr(Schema): + rule_ids: List[int] diff --git a/orochi/api/routers/rules.py b/orochi/api/routers/rules.py new file mode 100644 index 00000000..c979e9e7 --- /dev/null +++ b/orochi/api/routers/rules.py @@ -0,0 +1,153 @@ +import os +from typing import List + +import yara +from django.http import HttpResponse +from django.shortcuts import get_object_or_404 +from ninja import Query, Router +from ninja.security import django_auth + +from orochi.api.filters import RulesFilter +from orochi.api.models import ( + ErrorsOut, + ListStr, + RuleBuildSchema, + RulesOutSchema, + SuccessResponse, +) +from orochi.website.models import CustomRule +from orochi.ya.models import Rule + +router = Router() + + +@router.get("/", response={200: List[RulesOutSchema]}, auth=django_auth) +def list_rules(request, filters: Query[RulesFilter]): + return Rule.objects.all() + + +@router.get("/{pk}/download", auth=django_auth) +def download(request, pk: int): + """ + Download a rule file by its primary key. + + Args: + pk (int): The primary key of the rule to download. + + Returns: + HttpResponse: The HTTP response object containing the downloaded rule file. + + Raises: + Exception: If an error occurs during the process. + """ + try: + rule = Rule.objects.filter(pk=pk).filter(ruleset__enabled=True) + if rule.count() == 1: + rule = rule.first() + else: + return 400, {"errors": "Generic error"} + if os.path.exists(rule.path): + with open(rule.path, "rb") as f: + rule_data = f.read() + + response = HttpResponse( + rule_data, + content_type="application/text", + ) + response["Content-Disposition"] = ( + f"attachment; filename={os.path.basename(rule.path)}" + ) + return response + else: + return 400, {"errors": "Rule not found"} + except Exception as excp: + return 400, {"errors": str(excp)} + + +@router.delete( + "/", + auth=django_auth, + url_name="delete_rules", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def delete_rules(request, info: ListStr): + """ + Summary: + Delete rules based on the provided rule IDs. + + Explanation: + This function deletes rules based on the specified rule IDs belonging to the authenticated user. It removes the rules from the database and returns a success message upon deletion. + + Args: + - request: The request object. + - rule_ids: A list of integers representing the IDs of rules to be deleted. + + Returns: + - Tuple containing status code and a message dictionary. + + Raises: + - Any exception encountered during the process will result in a 400 status code with an error message. + """ + try: + rules = Rule.objects.filter(pk__in=info.rule_ids, ruleset__user=request.user) + rules.delete() + rules_count = rules.count() + if rules_count == 0: + return 200, {"message": f"{rules_count} rules deleted."} + else: + return 200, {"message": "Only rules in your ruleset can be deleted."} + except Exception as excp: + return 400, { + "errors": str(excp) if excp else "Generic error during rules deletion" + } + + +@router.post( + "/build", + response={200: SuccessResponse, 400: ErrorsOut}, + url_name="rule_build", + auth=django_auth, +) +def build_rules(request, info: RuleBuildSchema): + """ + Summary: + Build rules based on the provided information. + + Explanation: + This function builds rules using the provided information and saves them in a custom folder. It creates a new YARA rule file and stores it in the specified location. + + Args: + - request: The request object. + - info: An instance of RuleBuildSchema containing rule information. + + Returns: + - Tuple containing status code and a message dictionary. + + Raises: + - Any exception encountered during the process will result in a 400 status code with an error message. + """ + try: + rules = Rule.objects.filter(pk__in=info.rule_ids) + rules_file = {f"{rule.ruleset.name}_{rule.pk}": rule.path for rule in rules} + rules = yara.compile(filepaths=rules_file) + + # Manage duplicated file path + folder = f"/yara/customs/{request.user.username}" + os.makedirs(folder, exist_ok=True) + new_path = f"{folder}/{info.rulename}.yara" + filename, extension = os.path.splitext(new_path) + counter = 1 + while os.path.exists(new_path): + new_path = f"{filename}{counter}{extension}" + counter += 1 + + rules.save(new_path) + CustomRule.objects.create( + user=request.user, + path=new_path, + name=info.rulename, + ) + + return 200, {"message": f"Rule {info.rulename} created"} + except Exception as excp: + return 400, {"errors": str(excp)} diff --git a/orochi/templates/users/user_bookmarks.html b/orochi/templates/users/user_bookmarks.html index eda778fa..50088099 100644 --- a/orochi/templates/users/user_bookmarks.html +++ b/orochi/templates/users/user_bookmarks.html @@ -174,7 +174,7 @@ delay: 5000 }); }, - error: function () { + error: function (data) { $.toast({ title: 'Bookmark status!', content: data.message, @@ -217,7 +217,7 @@ delay: 5000 }); }, - error: function () { + error: function (data) { $.toast({ title: 'Bookmark status!', content: data.message, diff --git a/orochi/templates/users/user_rules.html b/orochi/templates/users/user_rules.html index a0cdb6d7..db724baa 100644 --- a/orochi/templates/users/user_rules.html +++ b/orochi/templates/users/user_rules.html @@ -143,7 +143,7 @@ { sortable: false, render: function (data, type, row, meta) { - let down = ``; + let down = ``; down += ``; return down; } @@ -204,15 +204,36 @@ if (rows_selected.length > 0) { bootbox.confirm("Delete selected rules in your ruleset?", function (result) { table.column(0).checkboxes.deselectAll(); + let obj = {}; var items = []; rows_selected.each(function (val) { items.push(val) }); + obj['rule_ids'] = items; + + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); + $.ajax({ - url: "{% url 'ya:delete' %}", - method: 'get', - data: { 'rules': items }, + url: "{% url 'api:delete_rules' %}", + method: 'delete', + data: JSON.stringify(obj), dataType: 'json', success: function (data) { table.ajax.reload(); + $.toast({ + title: 'Rules Deleted!', + content: data.message, + type: 'success', + delay: 5000 + }); + }, + error: function (data) { + $.toast({ + title: 'Delete Rules error!', + content: data.message, + type: 'error', + delay: 5000 + }); } }); }); @@ -226,11 +247,17 @@ bootbox.prompt("Select name for compiled custom rule:", function (result) { var items = []; rows_selected.each(function (val) { items.push(val) }); - var items_str = items.join(';'); + let obj = { + 'rule_ids': items, + 'rulename': result + }; + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); $.ajax({ - url: "{% url 'ya:build' %}", + url: "{% url 'api:rule_build' %}", method: 'post', - data: { 'rules': items_str, 'rulename': result, 'csrfmiddlewaretoken': $("input[name=csrfmiddlewaretoken").val() }, + data: JSON.stringify(obj), dataType: 'json', beforeSend: function () { if (items.length > 50) { @@ -246,6 +273,21 @@ if (items.length > 50) { dialog.modal('hide'); } + $.toast({ + title: 'Build Rule status!', + content: data.message, + type: 'success', + delay: 5000 + }); + }, + error: function (data) { + $.toast({ + title: 'Build Rule Error!', + content: data.message, + type: 'error', + delay: 5000 + }); + $("#modal-update").modal('hide'); } }); }); diff --git a/orochi/ya/models.py b/orochi/ya/models.py index c05057e1..dba65e27 100644 --- a/orochi/ya/models.py +++ b/orochi/ya/models.py @@ -1,7 +1,8 @@ -from django.db import models from django.contrib.auth import get_user_model -from django.db.models.signals import post_save, post_delete +from django.db import models +from django.db.models.signals import post_delete, post_save from django.dispatch import receiver + from orochi.ya.schema import RuleIndex @@ -34,7 +35,7 @@ class Rule(models.Model): ruleset = models.ForeignKey(Ruleset, on_delete=models.CASCADE, related_name="rules") def __str__(self): - return "[{}] {}".format(self.ruleset.name, self.path) + return f"[{self.ruleset.name}] {self.path}" @receiver(post_save, sender=Rule) diff --git a/orochi/ya/schema.py b/orochi/ya/schema.py index 171492b4..135f24cf 100644 --- a/orochi/ya/schema.py +++ b/orochi/ya/schema.py @@ -1,3 +1,4 @@ +import contextlib from pathlib import Path import elasticsearch @@ -34,10 +35,8 @@ def __init__(self): def create_index(self): if not self.es_client.indices.exists(index=self.index_name): - try: + with contextlib.suppress(elasticsearch.exceptions.RequestError): self.es_client.indices.create(index=self.index_name, body=self.schema) - except elasticsearch.exceptions.RequestError: - pass def delete_index(self): if self.es_client.indices.exists(index=self.index_name): diff --git a/orochi/ya/urls.py b/orochi/ya/urls.py index 26d7b9a8..348037e0 100644 --- a/orochi/ya/urls.py +++ b/orochi/ya/urls.py @@ -1,4 +1,5 @@ from django.urls import path + from orochi.ya import views app_name = "ya" @@ -11,8 +12,6 @@ ), path("list", views.list_rules, name="list"), path("upload", views.upload, name="upload"), - path("delete", views.delete, name="delete"), - path("build", views.build, name="build"), path("detail", views.detail, name="detail"), path("download_rule/", views.download_rule, name="download_rule"), ] diff --git a/orochi/ya/views.py b/orochi/ya/views.py index 6b61c3d1..a4086b50 100644 --- a/orochi/ya/views.py +++ b/orochi/ya/views.py @@ -2,7 +2,6 @@ import shutil from pathlib import Path -import yara from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required @@ -12,8 +11,8 @@ from django.http.response import HttpResponse from django.shortcuts import get_object_or_404, redirect from django.template.loader import render_to_string +from django.views.decorators.http import require_http_methods -from orochi.website.models import CustomRule from orochi.ya.forms import EditRuleForm, RuleForm from orochi.ya.models import Rule, Ruleset from orochi.ya.schema import RuleIndex @@ -96,86 +95,13 @@ def list_rules(request): return JsonResponse(return_data) -@login_required -def build(request): - """ - Creates fat yara from selected rules - """ - rules_id = request.POST.get("rules").split(";") - rulename = request.POST.get("rulename") - - rules = Rule.objects.filter(pk__in=rules_id) - - rules_file = {f"{rule.ruleset.name}_{rule.pk}": rule.path for rule in rules} - - rules = yara.compile(filepaths=rules_file) - - # Manage duplicated file path - folder = f"/yara/customs/{request.user.username}" - os.makedirs(folder, exist_ok=True) - new_path = f"{folder}/{rulename}.yara" - filename, extension = os.path.splitext(new_path) - counter = 1 - while os.path.exists(new_path): - new_path = f"{filename}{counter}{extension}" - counter += 1 - - rules.save(new_path) - CustomRule.objects.create( - user=request.user, - path=new_path, - name=rulename, - ) - - return JsonResponse({"ok": True}) - - -@login_required -def delete(request): - """ - Delete selected rules if in your ruleset - """ - rules_id = request.GET.getlist("rules[]") - rules = Rule.objects.filter(pk__in=rules_id, ruleset__user=request.user) - rules.delete() - return JsonResponse({"ok": True}) - - +@require_http_methods(["GET"]) @login_required def detail(request): """ Return content of rule """ data = {} - if request.method == "POST": - form = EditRuleForm(data=request.POST) - if form.is_valid(): - pk = request.POST.get("pk") - rule = get_object_or_404(Rule, pk=pk) - if rule.ruleset.user == request.user: - with open(rule.path, "w") as f: - f.write(request.POST.get("text")) - else: - ruleset = get_object_or_404(Ruleset, user=request.user) - user_path = ( - f"{settings.LOCAL_YARA_PATH}/{request.user.username}-Ruleset" - ) - os.makedirs(user_path, exist_ok=True) - rule.pk = None - rule.ruleset = ruleset - new_path = f"{user_path}/{Path(rule.path).name}" - filename, extension = os.path.splitext(new_path) - counter = 1 - while os.path.exists(new_path): - new_path = f"{filename}{counter}{extension}" - counter += 1 - with open(new_path, "w") as f: - f.write(request.POST.get("text")) - rule.path = new_path - rule.save() - return JsonResponse({"ok": True}) - raise Http404 - pk = request.GET.get("pk") rule = get_object_or_404(Rule, pk=pk) try: @@ -242,26 +168,3 @@ def upload(request): request=request, ) return JsonResponse(data) - - -@login_required -def download_rule(request, pk): - """ - Download selected rule - """ - rule = Rule.objects.filter(pk=pk).filter(ruleset__enabled=True) - if rule.count() == 1: - rule = rule.first() - else: - raise Http404 - - if os.path.exists(rule.path): - with open(rule.path, "rb") as fh: - response = HttpResponse( - fh.read(), content_type="application/force-download" - ) - response[ - "Content-Disposition" - ] = f"inline; filename={os.path.basename(rule.path)}" - return response - raise Http404("404") diff --git a/requirements/base.txt b/requirements/base.txt index 1cd7be5a..e5f24798 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,7 +7,7 @@ argon2-cffi==23.1.0 # https://github.com/evansd/whitenoise whitenoise==6.6.0 # https://github.com/andymccurdy/redis-py -redis==5.0.4 +redis==5.0.5 # https://github.com/redis/hiredis-py hiredis==2.3.2 # https://github.com/psycopg/psycopg2 @@ -28,7 +28,7 @@ channels_redis==4.2.0 # https://github.com/joke2k/django-environ django-environ==0.11.2 # https://github.com/pennersr/django-allauth -django-allauth==0.63.1 +django-allauth==0.63.3 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==2.1 # https://github.com/jazzband/django-redis @@ -64,18 +64,18 @@ django-admin-multiple-choice-list-filter==0.1.1 # Elasticsearch # ------------------------------------------------------------------------------ # https://github.com/elastic/elasticsearch-py -elasticsearch==8.13.1 +elasticsearch==8.14.0 # https://github.com/elastic/elasticsearch-dsl-py -elasticsearch-dsl==8.13.1 +elasticsearch-dsl==8.14.0 # https://github.com/jurismarches/luqum luqum==0.13.0 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.5.1 +dask==2024.5.2 # https://github.com/dask/distributed -distributed==2024.5.1 +distributed==2024.5.2 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.0.8 # https://github.com/python-lz4/python-lz4 @@ -87,7 +87,7 @@ cloudpickle==3.0.0 # https://pypi.org/project/toolz/ toolz==0.12.1 # https://pypi.org/project/tornado/ -tornado==6.4 +tornado==6.4.1 # https://pandas.pydata.org/ pandas==2.2.2 @@ -102,7 +102,8 @@ clamdpy==0.1.0.post1 # https://github.com/VirusTotal/vt-py vt-py==0.18.2 # https://github.com/mkorman90/regipy/ -regipy[full]==4.2.1 +#regipy[full]==4.2.1 +regipy[full] @ git+https://github.com/dadokkio/regipy@6d11c7dc4ef864d13bc84bc23ef2ca80cb0a90f0 # http://www.capstone-engine.org/ capstone==5.0.1 # https://github.com/Julian/jsonschema @@ -133,7 +134,7 @@ pefile==2023.2.7 # misp export # ------------------------------------------------------------------------------ # https://github.com/MISP/PyMISP -pymisp==2.4.190 +pymisp==2.4.193 # ldap # ------------------------------------------------------------------------------ diff --git a/requirements/local.txt b/requirements/local.txt index e3a5c767..78b8a27e 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -3,9 +3,9 @@ # Testing # ------------------------------------------------------------------------------ # https://github.com/python/mypy -mypy==1.9.0 +mypy==1.10.0 # https://github.com/typeddjango/django-stubs -django-stubs==5.0.0 +django-stubs==5.0.2 # https://github.com/pytest-dev/pytest pytest==8.1.1 # https://github.com/Frozenball/pytest-sugar @@ -18,7 +18,7 @@ flake8==7.0.0 # https://github.com/gforcada/flake8-isort flake8-isort==6.1.1 # https://github.com/nedbat/coveragepy -coverage==7.5.1 +coverage==7.5.3 # https://github.com/ambv/black black==24.4.2 # https://github.com/PyCQA/pylint-django @@ -31,7 +31,7 @@ pre-commit==3.7.1 # https://github.com/FactoryBoy/factory_boy factory-boy==3.3.0 # https://github.com/jazzband/django-debug-toolbar -django-debug-toolbar==4.3.0 +django-debug-toolbar==4.4.2 # https://github.com/django-extensions/django-extensions django-extensions==3.2.3 # https://github.com/nedbat/django_coverage_plugin From 0703234a6aff8fd1b4771da179d9a663edf1d65f Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Thu, 13 Jun 2024 16:19:50 +0200 Subject: [PATCH 54/84] #1073 wip --- orochi/api/api.py | 2 + orochi/api/models.py | 33 +++- orochi/api/routers/customrules.py | 187 ++++++++++++++++++ orochi/api/routers/rules.py | 67 ++++++- orochi/templates/users/user_bookmarks.html | 4 +- orochi/templates/users/user_rules.html | 97 +++++++-- ..._create.html => partial_index_create.html} | 0 ...tial_edit.html => partial_index_edit.html} | 2 +- ...tial_info.html => partial_index_info.html} | 0 ..._edit_rule.html => partial_rule_edit.html} | 6 +- ...ad_rules.html => partial_rule_upload.html} | 2 +- orochi/website/defaults.py | 2 +- orochi/website/urls.py | 4 - orochi/website/views.py | 94 +-------- orochi/ya/urls.py | 1 - orochi/ya/views.py | 32 +-- 16 files changed, 386 insertions(+), 147 deletions(-) create mode 100644 orochi/api/routers/customrules.py rename orochi/templates/website/{partial_create.html => partial_index_create.html} (100%) rename orochi/templates/website/{partial_edit.html => partial_index_edit.html} (99%) rename orochi/templates/website/{partial_info.html => partial_index_info.html} (100%) rename orochi/templates/ya/{partial_edit_rule.html => partial_rule_edit.html} (90%) rename orochi/templates/ya/{partial_upload_rules.html => partial_rule_upload.html} (99%) diff --git a/orochi/api/api.py b/orochi/api/api.py index 2cafa4af..e88975cd 100644 --- a/orochi/api/api.py +++ b/orochi/api/api.py @@ -2,6 +2,7 @@ from orochi.api.routers.auth import router as auth_router from orochi.api.routers.bookmarks import router as bookmarks_router +from orochi.api.routers.customrules import router as customrules_router from orochi.api.routers.dumps import router as dumps_router from orochi.api.routers.folders import router as folders_router from orochi.api.routers.plugins import router as plugins_router @@ -18,3 +19,4 @@ api.add_router("/utils/", utils_router, tags=["Utils"]) api.add_router("/bookmarks/", bookmarks_router, tags=["Bookmarks"]) api.add_router("/rules/", rules_router, tags=["Rules"]) +api.add_router("/customrules/", customrules_router, tags=["Custom Rules"]) diff --git a/orochi/api/models.py b/orochi/api/models.py index 9fa310e5..94f9e82a 100644 --- a/orochi/api/models.py +++ b/orochi/api/models.py @@ -1,3 +1,4 @@ +from enum import Enum from typing import Dict, List, Optional from django.contrib.auth import get_user_model @@ -6,9 +7,15 @@ from ninja.orm import create_schema from orochi.website.defaults import OSEnum -from orochi.website.models import Bookmark, Dump, Folder, Plugin +from orochi.website.models import Bookmark, CustomRule, Dump, Folder, Plugin from orochi.ya.models import Rule + +class RULE_ACTION(str, Enum): + PUBLISH = "Publish" + UNPUBLISH = "Unpublish" + + ################################################### # Auth ################################################### @@ -236,6 +243,21 @@ class BookmarksInSchema(Schema): query: Optional[str] = None +################################################### +# CustomRules +################################################### +class CustomRulesOutSchema(ModelSchema): + class Meta: + model = CustomRule + fields = ["id", "name", "path", "public", "user"] + + +class CustomRuleEditInSchema(ModelSchema): + class Meta: + model = CustomRule + fields = ["public"] + + ################################################### # Rules ################################################### @@ -252,3 +274,12 @@ class Meta: class ListStr(Schema): rule_ids: List[int] + + +class ListStrAction(Schema): + rule_ids: List[int] + action: RULE_ACTION + + +class RuleEditInSchena(Schema): + text: str diff --git a/orochi/api/routers/customrules.py b/orochi/api/routers/customrules.py new file mode 100644 index 00000000..6b47f59d --- /dev/null +++ b/orochi/api/routers/customrules.py @@ -0,0 +1,187 @@ +import os +import shutil +from typing import List + +from django.conf import settings +from django.db.models import Q +from django.http import HttpResponse +from ninja import Query, Router +from ninja.security import django_auth + +from orochi.api.filters import RulesFilter +from orochi.api.models import ( + RULE_ACTION, + CustomRulesOutSchema, + ErrorsOut, + ListStr, + ListStrAction, + SuccessResponse, +) +from orochi.website.models import CustomRule + +router = Router() + + +@router.get("/", response={200: List[CustomRulesOutSchema]}, auth=django_auth) +def list_custom_rules(request, filters: Query[RulesFilter]): + return CustomRule.objects.all() + + +@router.post( + "/{int:id}/default", + auth=django_auth, + url_name="default_customrule", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def default_rule(request, id: int): + """ + Set a custom rule as the default. + + Args: + request: The request object. + id (int): The ID of the custom rule to set as default. + + Returns: + tuple: A tuple containing the status code and a dictionary with a message. + + Raises: + Exception: If an error occurs during the process of setting the rule as default. + """ + try: + old_default = CustomRule.objects.filter(user=request.user, default=True) + if old_default.count() == 1: + old = old_default.first() + old.default = False + old.save() + + rule = CustomRule.objects.get(pk=id) + name = os.path.basename(rule.path) + if rule.user == request.user: + rule.default = True + rule.save() + return 200, {"message": f"Rule {name} set as default."} + # Make a copy + user_path = f"{settings.LOCAL_YARA_PATH}/{request.user.username}-Ruleset" + os.makedirs(user_path, exist_ok=True) + new_path = f"{user_path}/{rule.name}" + filename, extension = os.path.splitext(new_path) + counter = 1 + while os.path.exists(new_path): + new_path = f"{filename}{counter}{extension}" + counter += 1 + + shutil.copy(rule.path, new_path) + CustomRule.objects.create( + user=request.user, name=rule.name, path=new_path, default=True + ) + name = os.path.basename(new_path) + + return 200, { + "message": f"Rule {name} copied in your ruleset and set as default." + } + except Exception as excp: + return 400, {"errors": str(excp)} + + +@router.post( + "/publish", + auth=django_auth, + url_name="publish_customrule", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def publish_custom_rules(request, info: ListStrAction): + try: + rules = CustomRule.objects.filter(pk__in=info.rule_ids, user=request.user) + rules_count = rules.count() + for rule in rules: + rule.public = info.action == RULE_ACTION.PUBLISH + rule.save() + return 200, {"message": f"{rules_count} custom rules {info.action}ed."} + + except Exception as excp: + return 400, { + "errors": (str(excp) if excp else "Generic error during publishing") + } + + +@router.get("/{int:id}/download", auth=django_auth) +def download(request, id: int): + """ + Download a custom rule file by its primary key. + + Args: + pk (int): The primary key of the custom rule to download. + + Returns: + HttpResponse: The HTTP response object containing the downloaded custom rule file. + + Raises: + Exception: If an error occurs during the process. + """ + try: + rule = CustomRule.objects.filter(pk=id).filter( + Q(user=request.user) | Q(public=True) + ) + if rule.count() == 1: + rule = rule.first() + else: + return 400, {"errors": "Generic error"} + if os.path.exists(rule.path): + with open(rule.path, "rb") as f: + rule_data = f.read() + + response = HttpResponse( + rule_data, + content_type="application/text", + ) + response["Content-Disposition"] = ( + f"attachment; filename={os.path.basename(rule.path)}" + ) + return response + else: + return 400, {"errors": "Custom Rule not found"} + except Exception as excp: + return 400, {"errors": str(excp)} + + +@router.delete( + "/", + auth=django_auth, + url_name="delete_customrules", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def delete_custom_rules(request, info: ListStr): + """ + Summary: + Delete custom rules based on the provided rule IDs. + + Explanation: + This function deletes custom rules based on the specified rule IDs belonging to the authenticated user. It removes the rules from the database and returns a success message upon deletion. + + Args: + - request: The request object. + - rule_ids: A list of integers representing the IDs of custom rules to be deleted. + + Returns: + - Tuple containing status code and a message dictionary. + + Raises: + - Any exception encountered during the process will result in a 400 status code with an error message. + """ + try: + rules = CustomRule.objects.filter(pk__in=info.rule_ids, user=request.user) + rules_count = rules.count() + for rule in rules: + os.remove(rule.path) + rules.delete() + delete_message = f"{rules_count} custom rules deleted." + if rules_count != len(info.rule_ids): + delete_message += " Only custom rules in your ruleset have been deleted." + return 200, {"message": delete_message} + + except Exception as excp: + return 400, { + "errors": ( + str(excp) if excp else "Generic error during custom rules deletion" + ) + } diff --git a/orochi/api/routers/rules.py b/orochi/api/routers/rules.py index c979e9e7..aa6aea94 100644 --- a/orochi/api/routers/rules.py +++ b/orochi/api/routers/rules.py @@ -1,7 +1,9 @@ import os +from pathlib import Path from typing import List import yara +from django.conf import settings from django.http import HttpResponse from django.shortcuts import get_object_or_404 from ninja import Query, Router @@ -12,11 +14,12 @@ ErrorsOut, ListStr, RuleBuildSchema, + RuleEditInSchena, RulesOutSchema, SuccessResponse, ) from orochi.website.models import CustomRule -from orochi.ya.models import Rule +from orochi.ya.models import Rule, Ruleset router = Router() @@ -26,8 +29,53 @@ def list_rules(request, filters: Query[RulesFilter]): return Rule.objects.all() -@router.get("/{pk}/download", auth=django_auth) -def download(request, pk: int): +@router.patch( + "/{int:id}", + auth=django_auth, + url_name="edit_rule", + response={200: SuccessResponse, 400: ErrorsOut}, +) +def edit_rule(request, id: int, data: RuleEditInSchena): + """ + Edit or create a rule based on the provided primary key. + + Args: + pk (int): The primary key of the rule to edit or create. + + Returns: + tuple: A tuple containing the HTTP status code and a message indicating the success or error. + Raises: + Exception: If an error occurs during the process. + """ + try: + rule = get_object_or_404(Rule, pk=id) + name = os.path.basename(rule.path) + if rule.ruleset.user == request.user: + with open(rule.path, "w") as f: + f.write(data.text) + return 200, {"message": f"Rule {name} updated."} + ruleset = get_object_or_404(Ruleset, user=request.user) + user_path = f"{settings.LOCAL_YARA_PATH}/{request.user.username}-Ruleset" + os.makedirs(user_path, exist_ok=True) + rule.pk = None + rule.ruleset = ruleset + new_path = f"{user_path}/{Path(rule.path).name}" + filename, extension = os.path.splitext(new_path) + counter = 1 + while os.path.exists(new_path): + new_path = f"{filename}{counter}{extension}" + counter += 1 + with open(new_path, "w") as f: + f.write(data.text) + rule.path = new_path + rule.save() + return 200, {"message": f"Rule {name} created in local ruleset."} + except Exception as excp: + return 400, {"errors": str(excp)} + + +@router.get("/{int:id}/download", url_name="download_rule", auth=django_auth) +def download(request, id: int): """ Download a rule file by its primary key. @@ -41,7 +89,7 @@ def download(request, pk: int): Exception: If an error occurs during the process. """ try: - rule = Rule.objects.filter(pk=pk).filter(ruleset__enabled=True) + rule = Rule.objects.filter(pk=id).filter(ruleset__enabled=True) if rule.count() == 1: rule = rule.first() else: @@ -90,12 +138,13 @@ def delete_rules(request, info: ListStr): """ try: rules = Rule.objects.filter(pk__in=info.rule_ids, ruleset__user=request.user) - rules.delete() rules_count = rules.count() - if rules_count == 0: - return 200, {"message": f"{rules_count} rules deleted."} - else: - return 200, {"message": "Only rules in your ruleset can be deleted."} + rules.delete() + delete_message = f"{rules_count} rules deleted." + if rules_count != len(info.rule_ids): + delete_message += " Only rules in your ruleset have been deleted." + return 200, {"message": delete_message} + except Exception as excp: return 400, { "errors": str(excp) if excp else "Generic error during rules deletion" diff --git a/orochi/templates/users/user_bookmarks.html b/orochi/templates/users/user_bookmarks.html index 50088099..2530ed13 100644 --- a/orochi/templates/users/user_bookmarks.html +++ b/orochi/templates/users/user_bookmarks.html @@ -177,7 +177,7 @@ error: function (data) { $.toast({ title: 'Bookmark status!', - content: data.message, + content: data.errors, type: 'error', delay: 5000 }); @@ -220,7 +220,7 @@ error: function (data) { $.toast({ title: 'Bookmark status!', - content: data.message, + content: data.errors, type: 'error', delay: 5000 }); diff --git a/orochi/templates/users/user_rules.html b/orochi/templates/users/user_rules.html index db724baa..47349529 100644 --- a/orochi/templates/users/user_rules.html +++ b/orochi/templates/users/user_rules.html @@ -187,7 +187,7 @@ { sortable: false, render: function (data, type, row, meta) { - return ``; + return ``; } }, @@ -230,7 +230,7 @@ error: function (data) { $.toast({ title: 'Delete Rules error!', - content: data.message, + content: data.errors, type: 'error', delay: 5000 }); @@ -283,7 +283,7 @@ error: function (data) { $.toast({ title: 'Build Rule Error!', - content: data.message, + content: data.errors, type: 'error', delay: 5000 }); @@ -307,34 +307,46 @@ }, success: function (data) { $("#modal-update .modal-content").html(data.html_form); - initUploadFields(document.getElementById("rules-index")); + initUploadFields(document.getElementById("edit-rule")); } }); }); // UPLOAD RULE FORM SUBMIT - $(document).on("submit", "#rules-index", function (e) { + $(document).on("submit", "#edit-rule", function (e) { e.preventDefault(); var form = $(this); + + let formData = form.serializeArray(); + let obj = {}; + formData.forEach(item => { + if (item.name != 'csrfmiddlewaretoken') { + obj[item.name] = item.value; + } + }); + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); + $.ajax({ url: form.attr("action"), - data: form.serialize(), - type: form.attr("method"), + data: JSON.stringify(obj), + type: 'PATCH', dataType: 'json', success: function (data) { $("#modal-update").modal('hide'); table.ajax.reload(); $.toast({ title: 'Rules added!', - content: 'Rules added to your ruleset.', + content: data.message, type: 'success', delay: 5000 }); }, - error: function () { + error: function (data) { $.toast({ title: 'Error!', - content: 'Error during rule upload.', + content: data.errors, type: 'error', delay: 5000 }); @@ -375,15 +387,35 @@ if (rows_selected.length > 0) { bootbox.confirm("Delete selected custom rules?", function (result) { ruletable.column(0).checkboxes.deselectAll(); + let obj = {}; var items = []; rows_selected.each(function (val) { items.push(val) }); + obj['rule_ids'] = items; + + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); $.ajax({ - url: "{% url 'website:delete_rules' %}", - method: 'get', - data: { 'rules': items }, + url: "{% url 'api:delete_customrules' %}", + method: 'delete', + data: JSON.stringify(obj), dataType: 'json', success: function (data) { ruletable.ajax.reload(); + $.toast({ + title: 'Custom Rules Deleted!', + content: data.message, + type: 'success', + delay: 5000 + }); + }, + error: function (data) { + $.toast({ + title: 'Delete Custom Rules error!', + content: data.errors, + type: 'error', + delay: 5000 + }); } }); }); @@ -397,15 +429,31 @@ if (rows_selected.length > 0) { bootbox.confirm(action + " selected custom rules?", function (result) { ruletable.column(0).checkboxes.deselectAll(); + + let obj = {}; var items = []; rows_selected.each(function (val) { items.push(val) }); + obj['rule_ids'] = items; + obj['action'] = action; + + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); $.ajax({ - url: "{% url 'website:publish_rules' %}", - method: 'get', - data: { 'rules': items, 'action': action }, + url: "{% url 'api:publish_customrule' %}", + method: 'post', + data: JSON.stringify(obj), dataType: 'json', success: function (data) { ruletable.ajax.reload(); + }, + error: function (data) { + $.toast({ + title: 'Error performing action!', + content: data.errors, + type: 'error', + delay: 5000 + }); } }); }); @@ -416,13 +464,24 @@ $(document).on('click', '#star-rule', function () { var rule = $(this).data('pk'); bootbox.confirm("Make selected rule as default?", function (result) { + $.ajaxSetup({ + headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() } + }); + $.ajax({ - url: "{% url 'website:make_rule_default' %}", - method: 'get', - data: { 'rule': rule }, + url: "{% url 'api:default_customrule' id=123 %}".replace(/123/, rule), + method: 'post', dataType: 'json', success: function (data) { ruletable.ajax.reload(); + }, + error: function (data) { + $.toast({ + title: 'Error performing action!', + content: data.errors, + type: 'error', + delay: 5000 + }); } }); }) diff --git a/orochi/templates/website/partial_create.html b/orochi/templates/website/partial_index_create.html similarity index 100% rename from orochi/templates/website/partial_create.html rename to orochi/templates/website/partial_index_create.html diff --git a/orochi/templates/website/partial_edit.html b/orochi/templates/website/partial_index_edit.html similarity index 99% rename from orochi/templates/website/partial_edit.html rename to orochi/templates/website/partial_index_edit.html index d2be7376..e3a91ae4 100644 --- a/orochi/templates/website/partial_edit.html +++ b/orochi/templates/website/partial_index_edit.html @@ -25,4 +25,4 @@
    - \ No newline at end of file + diff --git a/orochi/templates/website/partial_info.html b/orochi/templates/website/partial_index_info.html similarity index 100% rename from orochi/templates/website/partial_info.html rename to orochi/templates/website/partial_index_info.html diff --git a/orochi/templates/ya/partial_edit_rule.html b/orochi/templates/ya/partial_rule_edit.html similarity index 90% rename from orochi/templates/ya/partial_edit_rule.html rename to orochi/templates/ya/partial_rule_edit.html index 7d8f817a..4130979f 100644 --- a/orochi/templates/ya/partial_edit_rule.html +++ b/orochi/templates/ya/partial_rule_edit.html @@ -1,6 +1,6 @@ {% load widget_tweaks %} -
    + {{ form.media }} {% csrf_token %} -
    \ No newline at end of file + diff --git a/orochi/templates/ya/partial_upload_rules.html b/orochi/templates/ya/partial_rule_upload.html similarity index 99% rename from orochi/templates/ya/partial_upload_rules.html rename to orochi/templates/ya/partial_rule_upload.html index 897897f6..885d9065 100644 --- a/orochi/templates/ya/partial_upload_rules.html +++ b/orochi/templates/ya/partial_rule_upload.html @@ -25,4 +25,4 @@
    - \ No newline at end of file + diff --git a/orochi/website/defaults.py b/orochi/website/defaults.py index 54f9fc8b..7aec62f3 100644 --- a/orochi/website/defaults.py +++ b/orochi/website/defaults.py @@ -10,7 +10,7 @@ class OSEnum(models.TextChoices): TOAST_RESULT_COLORS = { 0: "blue", - 1: "yellow", + 1: "#FFC300", 2: "green", 3: "green", 4: "orange", diff --git a/orochi/website/urls.py b/orochi/website/urls.py index fe98fc87..b82ae3f2 100644 --- a/orochi/website/urls.py +++ b/orochi/website/urls.py @@ -82,10 +82,6 @@ def to_url(self, value): path("update_symbols", views.update_symbols, name="update_symbols"), # RULES path("list_custom_rules", views.list_custom_rules, name="list_custom_rules"), - path("publish_rules", views.publish_rules, name="publish_rules"), - path("delete_rules", views.delete_rules, name="delete_rules"), - path("make_rule_default", views.make_rule_default, name="make_rule_default"), - path("download_rule/", views.download_rule, name="download_rule"), # SYMBOLS path("reload_symbols", views.reload_symbols, name="reload_symbols"), path("banner_symbols", views.banner_symbols, name="banner_symbols"), diff --git a/orochi/website/views.py b/orochi/website/views.py index c64561c7..7ffa95c6 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -36,7 +36,6 @@ from guardian.shortcuts import assign_perm, get_objects_for_user, get_perms, remove_perm from pymisp import MISPEvent, MISPObject, PyMISP from pymisp.tools import FileObject -from volatility3.framework import automagic, contexts from orochi.utils.download_symbols import Downloader from orochi.utils.volatility_dask_elk import ( @@ -77,6 +76,7 @@ Service, UserPlugin, ) +from volatility3.framework import automagic, contexts COLOR_TEMPLATE = """ ", views.download_rule, name="download_rule"), ] diff --git a/orochi/ya/views.py b/orochi/ya/views.py index a4086b50..22500d32 100644 --- a/orochi/ya/views.py +++ b/orochi/ya/views.py @@ -8,7 +8,6 @@ from django.core import management from django.db.models import Q from django.http import Http404, JsonResponse -from django.http.response import HttpResponse from django.shortcuts import get_object_or_404, redirect from django.template.loader import render_to_string from django.views.decorators.http import require_http_methods @@ -101,24 +100,27 @@ def detail(request): """ Return content of rule """ - data = {} pk = request.GET.get("pk") rule = get_object_or_404(Rule, pk=pk) try: with open(rule.path, "rb") as f: rule_data = f.read() - form = EditRuleForm( - initial={ - "text": "".join(rule_data.decode("utf-8", "replace")), - "pk": rule.pk, - } - ) - context = {"form": form} - data["html_form"] = render_to_string( - "ya/partial_edit_rule.html", - context, - request=request, - ) + context = { + "form": EditRuleForm( + initial={ + "text": "".join(rule_data.decode("utf-8", "replace")), + "pk": rule.pk, + } + ), + "id": rule.pk, + } + data = { + "html_form": render_to_string( + "ya/partial_rule_edit.html", + context, + request=request, + ) + } return JsonResponse(data) except UnicodeDecodeError as e: raise Http404 from e @@ -163,7 +165,7 @@ def upload(request): form = RuleForm() context = {"form": form} data["html_form"] = render_to_string( - "ya/partial_upload_rules.html", + "ya/partial_rule_upload.html", context, request=request, ) From f8c00995f718c8891443bd356d32a510da513306 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 30 Jul 2024 10:58:25 +0200 Subject: [PATCH 55/84] 2fa, update libs, yara-x --- .envs/.local/.postgres | 2 +- compose/local/dask/Dockerfile | 24 +----- compose/local/django/Dockerfile | 30 +------ config/settings/base.py | 5 +- orochi/api/filters.py | 12 +-- orochi/api/models.py | 24 +++++- orochi/api/routers/customrules.py | 10 +-- orochi/api/routers/rules.py | 24 +++--- .../templates/account/account_inactive.html | 12 --- orochi/templates/account/email.html | 80 ------------------- orochi/templates/account/email_confirm.html | 32 -------- orochi/templates/account/login.html | 29 ------- orochi/templates/account/logout.html | 22 ----- orochi/templates/account/password_change.html | 17 ---- orochi/templates/account/password_reset.html | 19 ----- .../account/password_reset_done.html | 17 ---- .../account/password_reset_from_key.html | 25 ------ .../account/password_reset_from_key_done.html | 10 --- orochi/templates/account/password_set.html | 17 ---- orochi/templates/account/signup.html | 23 ------ orochi/templates/account/signup_closed.html | 12 --- .../templates/account/verification_sent.html | 13 --- .../account/verified_email_required.html | 24 ------ orochi/templates/allauth/elements/alert.html | 5 ++ orochi/templates/allauth/elements/badge.html | 19 +++++ orochi/templates/allauth/elements/button.html | 31 +++++++ .../allauth/elements/button__entrance.html | 6 ++ .../allauth/elements/button_group.html | 5 ++ orochi/templates/allauth/elements/field.html | 78 ++++++++++++++++++ orochi/templates/allauth/elements/fields.html | 11 +++ orochi/templates/allauth/elements/form.html | 14 ++++ .../allauth/elements/form__entrance.html | 2 + orochi/templates/allauth/elements/h1.html | 5 ++ .../allauth/elements/h1__entrance.html | 5 ++ .../allauth/elements/h2__entrance.html | 5 ++ orochi/templates/allauth/elements/img.html | 5 ++ orochi/templates/allauth/elements/panel.html | 17 ++++ .../templates/allauth/elements/provider.html | 4 + .../allauth/elements/provider_list.html | 5 ++ orochi/templates/allauth/elements/table.html | 5 ++ orochi/templates/allauth/layouts/base.html | 8 ++ .../templates/allauth/layouts/entrance.html | 26 ++++++ orochi/templates/allauth/layouts/manage.html | 61 ++++++++++++++ orochi/templates/base.html | 39 ++++++++- orochi/users/adapters.py | 16 ---- orochi/utils/volatility_dask_elk.py | 2 +- orochi/website/admin.py | 8 +- .../commands/generate_default_rule.py | 13 ++- orochi/ya/management/commands/rules_sync.py | 11 +-- requirements/base.txt | 42 +++++----- requirements/local.txt | 8 +- setup.cfg | 2 +- 52 files changed, 443 insertions(+), 498 deletions(-) delete mode 100644 orochi/templates/account/account_inactive.html delete mode 100644 orochi/templates/account/email.html delete mode 100644 orochi/templates/account/email_confirm.html delete mode 100644 orochi/templates/account/login.html delete mode 100644 orochi/templates/account/logout.html delete mode 100644 orochi/templates/account/password_change.html delete mode 100644 orochi/templates/account/password_reset.html delete mode 100644 orochi/templates/account/password_reset_done.html delete mode 100644 orochi/templates/account/password_reset_from_key.html delete mode 100644 orochi/templates/account/password_reset_from_key_done.html delete mode 100644 orochi/templates/account/password_set.html delete mode 100644 orochi/templates/account/signup.html delete mode 100644 orochi/templates/account/signup_closed.html delete mode 100644 orochi/templates/account/verification_sent.html delete mode 100644 orochi/templates/account/verified_email_required.html create mode 100644 orochi/templates/allauth/elements/alert.html create mode 100644 orochi/templates/allauth/elements/badge.html create mode 100644 orochi/templates/allauth/elements/button.html create mode 100644 orochi/templates/allauth/elements/button__entrance.html create mode 100644 orochi/templates/allauth/elements/button_group.html create mode 100644 orochi/templates/allauth/elements/field.html create mode 100644 orochi/templates/allauth/elements/fields.html create mode 100644 orochi/templates/allauth/elements/form.html create mode 100644 orochi/templates/allauth/elements/form__entrance.html create mode 100644 orochi/templates/allauth/elements/h1.html create mode 100644 orochi/templates/allauth/elements/h1__entrance.html create mode 100644 orochi/templates/allauth/elements/h2__entrance.html create mode 100644 orochi/templates/allauth/elements/img.html create mode 100644 orochi/templates/allauth/elements/panel.html create mode 100644 orochi/templates/allauth/elements/provider.html create mode 100644 orochi/templates/allauth/elements/provider_list.html create mode 100644 orochi/templates/allauth/elements/table.html create mode 100644 orochi/templates/allauth/layouts/base.html create mode 100644 orochi/templates/allauth/layouts/entrance.html create mode 100644 orochi/templates/allauth/layouts/manage.html delete mode 100644 orochi/users/adapters.py diff --git a/.envs/.local/.postgres b/.envs/.local/.postgres index bfb10230..c3026c14 100755 --- a/.envs/.local/.postgres +++ b/.envs/.local/.postgres @@ -5,4 +5,4 @@ POSTGRES_PORT=5432 POSTGRES_DB=orochi POSTGRES_USER=debug POSTGRES_PASSWORD=debug -DATABASE_URL=postgresql://debug:debug@posgtgres:5432/orochi +DATABASE_URL=postgresql://debug:debug@postgres:5432/orochi diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 0c4078aa..41c8cab2 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.5.2-py3.12 +FROM daskdev/dask:2024.7.1-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -16,8 +16,6 @@ RUN apt-get --allow-releaseinfo-change update \ gettext \ # Clamav clamav-daemon clamav-freshclam clamav-unofficial-sigs \ - # requirement to compile yara - automake libtool make gcc pkg-config flex bison libssl-dev libjansson-dev libmagic-dev \ # cleaning up unused files && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && rm -rf /var/lib/apt/lists/* @@ -26,28 +24,10 @@ RUN apt-get --allow-releaseinfo-change update \ COPY ./compose/local/clamav/freshclam.conf /etc/clamav/freshclam.conf RUN freshclam -WORKDIR /tmp -RUN git clone --recursive https://github.com/VirusTotal/yara.git -WORKDIR /tmp/yara -RUN ./bootstrap.sh \ - && ./configure --enable-cuckoo \ - --enable-magic \ - --enable-dotnet \ - --with-crypto \ - && make \ - && make install \ - && echo "Install yara-python..." -WORKDIR /tmp -RUN git clone --branch v4.3.x --recursive https://github.com/VirusTotal/yara-python -WORKDIR /tmp/yara-python -RUN python setup.py build \ - && python setup.py install \ - && rm -rf /tmp/* - # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.2.10 -e git+https://github.com/volatilityfoundation/volatility3.git@543a39485bdf57df47d731b55ab112e04f3033f0#egg=volatility3 \ +RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@dc8dc9b078d42e41698ff93f2e65c5ee99aa2172#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index b21fdd95..75741ad1 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.3-slim-bookworm as common-base +FROM python:3.12.4-slim-bookworm as common-base ENV DJANGO_SETTINGS_MODULE config.settings.local ENV PYTHONUNBUFFERED 1 @@ -17,7 +17,7 @@ RUN apt-get update \ libmagic1 p7zip-full \ # Translations dependencies gettext \ - # git from yara cloning + # git for cloning git \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -30,30 +30,10 @@ RUN apt-get update \ && apt-get install --no-install-recommends -y \ # utils curl unzip \ - # requirement to compile yara - automake libtool make gcc pkg-config flex bison libssl-dev libjansson-dev libmagic-dev \ # cleaning up unused files && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && rm -rf /var/lib/apt/lists/* -# Build yara and yara-python from sources -FROM base-builder as yara-builder -WORKDIR /tmp -RUN git clone --recursive https://github.com/VirusTotal/yara.git -WORKDIR /tmp/yara -RUN ./bootstrap.sh \ - && ./configure --enable-cuckoo \ - --enable-magic \ - --enable-dotnet \ - --with-crypto \ - && make \ - && make install \ - && echo "Install yara-python..." -WORKDIR /tmp -RUN git clone --branch v4.3.x --recursive https://github.com/VirusTotal/yara-python -WORKDIR /tmp/yara-python -RUN python setup.py build - FROM base-builder as go-builder WORKDIR / RUN curl https://dl.google.com/go/go1.22.0.linux-amd64.tar.gz --output go1.22.0.linux-amd64.tar.gz \ @@ -65,7 +45,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.2.10 -e git+https://github.com/volatilityfoundation/volatility3.git@543a39485bdf57df47d731b55ab112e04f3033f0#egg=volatility3 \ +RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@dc8dc9b078d42e41698ff93f2e65c5ee99aa2172#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py @@ -89,10 +69,6 @@ RUN sed -i 's/\r$//g' /start RUN chmod +x /start COPY --from=go-builder /dwarf2json/dwarf2json /dwarf2json/dwarf2json -# Install yara-python -COPY --from=yara-builder /tmp/yara-python/ /tmp/ -WORKDIR /tmp -RUN python setup.py install WORKDIR /app ENTRYPOINT ["/entrypoint"] diff --git a/config/settings/base.py b/config/settings/base.py index 65eec6da..796b9f91 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -60,7 +60,7 @@ THIRD_PARTY_APPS = [ "allauth", "allauth.account", - "allauth.socialaccount", + "allauth.mfa", "colorfield", "crispy_forms", "crispy_bootstrap5", @@ -248,8 +248,7 @@ ACCOUNT_AUTHENTICATION_METHOD = "username" ACCOUNT_EMAIL_REQUIRED = False ACCOUNT_EMAIL_VERIFICATION = "optional" -ACCOUNT_ADAPTER = "orochi.users.adapters.AccountAdapter" -SOCIALACCOUNT_ADAPTER = "orochi.users.adapters.SocialAccountAdapter" +ACCOUNT_ADAPTER = "allauth.account.adapter.DefaultAccountAdapter" # Elasticsearch # ------------------------------------------------------------------------------- diff --git a/orochi/api/filters.py b/orochi/api/filters.py index f19878c9..243cb552 100644 --- a/orochi/api/filters.py +++ b/orochi/api/filters.py @@ -2,7 +2,6 @@ from typing import List from ninja import Schema -from pydantic import root_validator class OPERATING_SYSTEM(str, Enum): @@ -21,7 +20,7 @@ class DumpFilters(Schema): ################################################### -# Rules +# DatatableFilter ################################################### class Search(Schema): value: str = None @@ -29,7 +28,7 @@ class Search(Schema): class Column(Schema): - data: int + data: int = 0 name: str = None searchable: bool = True orderable: bool = True @@ -41,13 +40,10 @@ class Order(Schema): dir: str = "asc" -class RulesFilter(Schema): +class DatatableFilter(Schema): + draw: int = 0 start: int = 0 length: int = 10 columns: List[Column] = [] search: Search = None order: List[Order] = [] - - @root_validator(pre=True) - def extract_data(cls, v): - return v diff --git a/orochi/api/models.py b/orochi/api/models.py index 94f9e82a..d382b327 100644 --- a/orochi/api/models.py +++ b/orochi/api/models.py @@ -246,10 +246,28 @@ class BookmarksInSchema(Schema): ################################################### # CustomRules ################################################### -class CustomRulesOutSchema(ModelSchema): + + +class User(ModelSchema): + class Meta: - model = CustomRule - fields = ["id", "name", "path", "public", "user"] + model = get_user_model() + fields = ["username"] + + +class RuleData(Schema): + id: int + name: str + path: str + user: str + public: bool + default: bool + + +class CustomRulesOutSchema(Schema): + recordsTotal: int + recordsFiltered: int + data: List[RuleData] class CustomRuleEditInSchema(ModelSchema): diff --git a/orochi/api/routers/customrules.py b/orochi/api/routers/customrules.py index 6b47f59d..5ca4ab0f 100644 --- a/orochi/api/routers/customrules.py +++ b/orochi/api/routers/customrules.py @@ -1,17 +1,14 @@ import os import shutil -from typing import List from django.conf import settings from django.db.models import Q from django.http import HttpResponse -from ninja import Query, Router +from ninja import Router from ninja.security import django_auth -from orochi.api.filters import RulesFilter from orochi.api.models import ( RULE_ACTION, - CustomRulesOutSchema, ErrorsOut, ListStr, ListStrAction, @@ -22,11 +19,6 @@ router = Router() -@router.get("/", response={200: List[CustomRulesOutSchema]}, auth=django_auth) -def list_custom_rules(request, filters: Query[RulesFilter]): - return CustomRule.objects.all() - - @router.post( "/{int:id}/default", auth=django_auth, diff --git a/orochi/api/routers/rules.py b/orochi/api/routers/rules.py index aa6aea94..0e3cc865 100644 --- a/orochi/api/routers/rules.py +++ b/orochi/api/routers/rules.py @@ -1,21 +1,18 @@ import os from pathlib import Path -from typing import List -import yara +import yara_x from django.conf import settings from django.http import HttpResponse from django.shortcuts import get_object_or_404 -from ninja import Query, Router +from ninja import Router from ninja.security import django_auth -from orochi.api.filters import RulesFilter from orochi.api.models import ( ErrorsOut, ListStr, RuleBuildSchema, RuleEditInSchena, - RulesOutSchema, SuccessResponse, ) from orochi.website.models import CustomRule @@ -24,11 +21,6 @@ router = Router() -@router.get("/", response={200: List[RulesOutSchema]}, auth=django_auth) -def list_rules(request, filters: Query[RulesFilter]): - return Rule.objects.all() - - @router.patch( "/{int:id}", auth=django_auth, @@ -177,8 +169,12 @@ def build_rules(request, info: RuleBuildSchema): """ try: rules = Rule.objects.filter(pk__in=info.rule_ids) - rules_file = {f"{rule.ruleset.name}_{rule.pk}": rule.path for rule in rules} - rules = yara.compile(filepaths=rules_file) + + compiler = yara_x.Compiler() + for rule in rules: + with open(rule.path, "r") as fp: + compiler.add_source(fp.read()) + rules = compiler.build() # Manage duplicated file path folder = f"/yara/customs/{request.user.username}" @@ -189,8 +185,8 @@ def build_rules(request, info: RuleBuildSchema): while os.path.exists(new_path): new_path = f"{filename}{counter}{extension}" counter += 1 - - rules.save(new_path) + with open(new_path, "wb") as fo: + rules.serialize_into(fo) CustomRule.objects.create( user=request.user, path=new_path, diff --git a/orochi/templates/account/account_inactive.html b/orochi/templates/account/account_inactive.html deleted file mode 100644 index 17c21577..00000000 --- a/orochi/templates/account/account_inactive.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Account Inactive" %}{% endblock %} - -{% block inner %} -

    {% trans "Account Inactive" %}

    - -

    {% trans "This account is inactive." %}

    -{% endblock %} - diff --git a/orochi/templates/account/email.html b/orochi/templates/account/email.html deleted file mode 100644 index 0dc8d145..00000000 --- a/orochi/templates/account/email.html +++ /dev/null @@ -1,80 +0,0 @@ - -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Account" %}{% endblock %} - -{% block inner %} -

    {% trans "E-mail Addresses" %}

    - -{% if user.emailaddress_set.all %} -

    {% trans 'The following e-mail addresses are associated with your account:' %}

    - - - -{% else %} -

    {% trans 'Warning:'%} {% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}

    - -{% endif %} - - -

    {% trans "Add E-mail Address" %}

    - -
    - {% csrf_token %} - {{ form|crispy }} - -
    - -{% endblock %} - - -{% block javascript %} -{{ block.super }} - -{% endblock %} - diff --git a/orochi/templates/account/email_confirm.html b/orochi/templates/account/email_confirm.html deleted file mode 100644 index 46c78126..00000000 --- a/orochi/templates/account/email_confirm.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %} - - -{% block inner %} -

    {% trans "Confirm E-mail Address" %}

    - -{% if confirmation %} - -{% user_display confirmation.email_address.user as user_display %} - -

    {% blocktrans with confirmation.email_address.email as email %}Please confirm that {{ email }} is an e-mail address for user {{ user_display }}.{% endblocktrans %}

    - -
    -{% csrf_token %} - -
    - -{% else %} - -{% url 'account_email' as email_url %} - -

    {% blocktrans %}This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request.{% endblocktrans %}

    - -{% endif %} - -{% endblock %} - diff --git a/orochi/templates/account/login.html b/orochi/templates/account/login.html deleted file mode 100644 index 3f4e65a6..00000000 --- a/orochi/templates/account/login.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account socialaccount %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Sign In" %}{% endblock %} - -{% block inner %} - -

    {% trans "Sign In" %}

    - -

    - {% blocktrans %} - If you have not created an account yet, then please sign up first. - {% endblocktrans %} -

    - - - -{% endblock %} \ No newline at end of file diff --git a/orochi/templates/account/logout.html b/orochi/templates/account/logout.html deleted file mode 100644 index 8e2e6754..00000000 --- a/orochi/templates/account/logout.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Sign Out" %}{% endblock %} - -{% block inner %} -

    {% trans "Sign Out" %}

    - -

    {% trans 'Are you sure you want to sign out?' %}

    - -
    - {% csrf_token %} - {% if redirect_field_value %} - - {% endif %} - -
    - - -{% endblock %} - diff --git a/orochi/templates/account/password_change.html b/orochi/templates/account/password_change.html deleted file mode 100644 index b72ca068..00000000 --- a/orochi/templates/account/password_change.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block inner %} -

    {% trans "Change Password" %}

    - -
    - {% csrf_token %} - {{ form|crispy }} - -
    -{% endblock %} - diff --git a/orochi/templates/account/password_reset.html b/orochi/templates/account/password_reset.html deleted file mode 100644 index f116ef6b..00000000 --- a/orochi/templates/account/password_reset.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Password Reset" %}{% endblock %} - -{% block inner %} - -

    {% trans "Password Reset" %}

    - -
    - {% csrf_token %} - {{ form|crispy }} - -
    - -{% endblock %} \ No newline at end of file diff --git a/orochi/templates/account/password_reset_done.html b/orochi/templates/account/password_reset_done.html deleted file mode 100644 index c59534af..00000000 --- a/orochi/templates/account/password_reset_done.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Password Reset" %}{% endblock %} - -{% block inner %} -

    {% trans "Password Reset" %}

    - - {% if user.is_authenticated %} - {% include "account/snippets/already_logged_in.html" %} - {% endif %} - -

    {% blocktrans %}We have sent you an e-mail. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}

    -{% endblock %} - diff --git a/orochi/templates/account/password_reset_from_key.html b/orochi/templates/account/password_reset_from_key.html deleted file mode 100644 index 4abdb562..00000000 --- a/orochi/templates/account/password_reset_from_key.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block inner %} -

    {% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}

    - - {% if token_fail %} - {% url 'account_reset_password' as passwd_reset_url %} -

    {% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a new password reset.{% endblocktrans %}

    - {% else %} - {% if form %} -
    - {% csrf_token %} - {{ form|crispy }} - -
    - {% else %} -

    {% trans 'Your password is now changed.' %}

    - {% endif %} - {% endif %} -{% endblock %} - diff --git a/orochi/templates/account/password_reset_from_key_done.html b/orochi/templates/account/password_reset_from_key_done.html deleted file mode 100644 index 89be086f..00000000 --- a/orochi/templates/account/password_reset_from_key_done.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block inner %} -

    {% trans "Change Password" %}

    -

    {% trans 'Your password is now changed.' %}

    -{% endblock %} - diff --git a/orochi/templates/account/password_set.html b/orochi/templates/account/password_set.html deleted file mode 100644 index 22322235..00000000 --- a/orochi/templates/account/password_set.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Set Password" %}{% endblock %} - -{% block inner %} -

    {% trans "Set Password" %}

    - -
    - {% csrf_token %} - {{ form|crispy }} - -
    -{% endblock %} - diff --git a/orochi/templates/account/signup.html b/orochi/templates/account/signup.html deleted file mode 100644 index 6a2954eb..00000000 --- a/orochi/templates/account/signup.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %}{% trans "Signup" %}{% endblock %} - -{% block inner %} -

    {% trans "Sign Up" %}

    - -

    {% blocktrans %}Already have an account? Then please sign in.{% endblocktrans %}

    - - - -{% endblock %} - diff --git a/orochi/templates/account/signup_closed.html b/orochi/templates/account/signup_closed.html deleted file mode 100644 index 2322f176..00000000 --- a/orochi/templates/account/signup_closed.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Sign Up Closed" %}{% endblock %} - -{% block inner %} -

    {% trans "Sign Up Closed" %}

    - -

    {% trans "We are sorry, but the sign up is currently closed." %}

    -{% endblock %} - diff --git a/orochi/templates/account/verification_sent.html b/orochi/templates/account/verification_sent.html deleted file mode 100644 index ad093fd4..00000000 --- a/orochi/templates/account/verification_sent.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} - -{% block inner %} -

    {% trans "Verify Your E-mail Address" %}

    - -

    {% blocktrans %}We have sent an e-mail to you for verification. Follow the link provided to finalize the signup process. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}

    - -{% endblock %} - diff --git a/orochi/templates/account/verified_email_required.html b/orochi/templates/account/verified_email_required.html deleted file mode 100644 index 09d4fde7..00000000 --- a/orochi/templates/account/verified_email_required.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} - -{% block inner %} -

    {% trans "Verify Your E-mail Address" %}

    - -{% url 'account_email' as email_url %} - -

    {% blocktrans %}This part of the site requires us to verify that -you are who you claim to be. For this purpose, we require that you -verify ownership of your e-mail address. {% endblocktrans %}

    - -

    {% blocktrans %}We have sent an e-mail to you for -verification. Please click on the link inside this e-mail. Please -contact us if you do not receive it within a few minutes.{% endblocktrans %}

    - -

    {% blocktrans %}Note: you can still change your e-mail address.{% endblocktrans %}

    - - -{% endblock %} - diff --git a/orochi/templates/allauth/elements/alert.html b/orochi/templates/allauth/elements/alert.html new file mode 100644 index 00000000..eeca1c4a --- /dev/null +++ b/orochi/templates/allauth/elements/alert.html @@ -0,0 +1,5 @@ +{% load allauth %} +
    + {% slot message %} + {% endslot %} +
    diff --git a/orochi/templates/allauth/elements/badge.html b/orochi/templates/allauth/elements/badge.html new file mode 100644 index 00000000..91f44d09 --- /dev/null +++ b/orochi/templates/allauth/elements/badge.html @@ -0,0 +1,19 @@ +{% load allauth %} +{% setvar variant %} + {% if "warning" in attrs.tags %} + warning + {% elif "danger" in attrs.tags %} + danger + {% elif "secondary" in attrs.tags %} + secondary + {% elif "success" in attrs.tags %} + success + {% else %} + primary + {% endif %} +{% endsetvar %} + + {% slot %} + {% endslot %} + diff --git a/orochi/templates/allauth/elements/button.html b/orochi/templates/allauth/elements/button.html new file mode 100644 index 00000000..9c6848bc --- /dev/null +++ b/orochi/templates/allauth/elements/button.html @@ -0,0 +1,31 @@ +{% load allauth %} +{% comment %} djlint:off {% endcomment %} +<{% if attrs.href %}a href="{{ attrs.href }}"{% else %}button{% endif %} +{% if attrs.form %}form="{{ attrs.form }}"{% endif %} +{% if attrs.id %}id="{{ attrs.id }}"{% endif %} +{% if attrs.name %}name="{{ attrs.name }}"{% endif %} +{% if attrs.type %}type="{{ attrs.type }}"{% endif %} +{% if attrs.value %}value="{{ attrs.value }}"{% endif %} +class="{% block class %} + btn + {% if "link" in attrs.tags %}btn-link + {% else %} + {% if "prominent" in attrs.tags %}btn-lg{% elif "minor" in attrs.tags %}btn-sm{% endif %} + btn-{% if 'outline' in attrs.tags %}outline-{% endif %}{% if "danger" in attrs.tags %}danger{% elif "secondary" in attrs.tags %}secondary{% elif "warning" in attrs.tags %}warning{% else %}primary{% endif %} + {% endif %}{% endblock %}"> + {% if "tool" in attrs.tags %} + {% if "delete" in attrs.tags %} + + + + + {% elif "edit" in attrs.tags %} + + {% endif %} + {% endif %} + +{% if not "tool" in attrs.tags %} +{% slot %} +{% endslot %} +{% endif %} + diff --git a/orochi/templates/allauth/elements/button__entrance.html b/orochi/templates/allauth/elements/button__entrance.html new file mode 100644 index 00000000..a5d0b233 --- /dev/null +++ b/orochi/templates/allauth/elements/button__entrance.html @@ -0,0 +1,6 @@ +{% extends "allauth/elements/button.html" %} +{% load allauth %} +{% block class %} + {{ block.super }} + w-100 +{% endblock %} diff --git a/orochi/templates/allauth/elements/button_group.html b/orochi/templates/allauth/elements/button_group.html new file mode 100644 index 00000000..3f9214b1 --- /dev/null +++ b/orochi/templates/allauth/elements/button_group.html @@ -0,0 +1,5 @@ +{% load allauth %} +
    + {% slot %} + {% endslot %} +
    diff --git a/orochi/templates/allauth/elements/field.html b/orochi/templates/allauth/elements/field.html new file mode 100644 index 00000000..7000d291 --- /dev/null +++ b/orochi/templates/allauth/elements/field.html @@ -0,0 +1,78 @@ +{% load allauth %} +{% if attrs.type == "checkbox" or attrs.type == "radio" %} +
    + + + {% if slots.help_text %} +
    + {% slot help_text %} + {% endslot %} +
    + {% endif %} +
    +{% elif attrs.type == "textarea" %} +
    + + +
    +{% elif attrs.type == "hidden" %} + +{% else %} +
    + {% if not attrs.unlabeled %} + + {% endif %} + + {% if attrs.unlabeled %} + + {% endif %} + {% if slots.help_text %} +
    + {% slot help_text %} + {% endslot %} +
    + {% endif %} + {% if attrs.errors %} + {% for error in attrs.errors %}
    {{ error }}
    {% endfor %} + {% endif %} +
    +{% endif %} diff --git a/orochi/templates/allauth/elements/fields.html b/orochi/templates/allauth/elements/fields.html new file mode 100644 index 00000000..47fb273e --- /dev/null +++ b/orochi/templates/allauth/elements/fields.html @@ -0,0 +1,11 @@ +{% load allauth %} +{% for bound_field in attrs.form %} + {% element field unlabeled=attrs.unlabeled name=bound_field.name type=bound_field.field.widget.input_type required=bound_field.field.required value=bound_field.value id=bound_field.auto_id errors=bound_field.errors placeholder=bound_field.field.widget.attrs.placeholder tabindex=bound_field.field.widget.attrs.tabindex autocomplete=bound_field.field.widget.attrs.autocomplete style=bound_field.field.widget.attrs.style %} + {% slot label %} + {{ bound_field.label }} + {% endslot %} + {% slot help_text %} + {{ bound_field.field.help_text }} + {% endslot %} + {% endelement %} +{% endfor %} diff --git a/orochi/templates/allauth/elements/form.html b/orochi/templates/allauth/elements/form.html new file mode 100644 index 00000000..716c02a9 --- /dev/null +++ b/orochi/templates/allauth/elements/form.html @@ -0,0 +1,14 @@ +{% load allauth %} +{% for err in attrs.form.non_field_errors %}
    {{ err }}
    {% endfor %} +
    + {% if not attrs.no_visible_fields %}
    {% endif %} + {% slot body %} + {% endslot %} + {% if not attrs.no_visible_fields %}
    {% endif %} + {% if not attrs.no_visible_fields %}{% endif %} +
    diff --git a/orochi/templates/allauth/elements/form__entrance.html b/orochi/templates/allauth/elements/form__entrance.html new file mode 100644 index 00000000..abb1a62f --- /dev/null +++ b/orochi/templates/allauth/elements/form__entrance.html @@ -0,0 +1,2 @@ +{% extends "allauth/elements/form.html" %} +{% block form_class %}{% endblock %} diff --git a/orochi/templates/allauth/elements/h1.html b/orochi/templates/allauth/elements/h1.html new file mode 100644 index 00000000..f76e46f1 --- /dev/null +++ b/orochi/templates/allauth/elements/h1.html @@ -0,0 +1,5 @@ +{% load allauth %} +

    + {% slot %} + {% endslot %} +

    diff --git a/orochi/templates/allauth/elements/h1__entrance.html b/orochi/templates/allauth/elements/h1__entrance.html new file mode 100644 index 00000000..16634195 --- /dev/null +++ b/orochi/templates/allauth/elements/h1__entrance.html @@ -0,0 +1,5 @@ +{% load allauth %} +

    + {% slot %} + {% endslot %} +

    diff --git a/orochi/templates/allauth/elements/h2__entrance.html b/orochi/templates/allauth/elements/h2__entrance.html new file mode 100644 index 00000000..37fd2912 --- /dev/null +++ b/orochi/templates/allauth/elements/h2__entrance.html @@ -0,0 +1,5 @@ +{% load allauth %} +

    + {% slot %} + {% endslot %} +

    diff --git a/orochi/templates/allauth/elements/img.html b/orochi/templates/allauth/elements/img.html new file mode 100644 index 00000000..a356bca1 --- /dev/null +++ b/orochi/templates/allauth/elements/img.html @@ -0,0 +1,5 @@ +
    + +
    diff --git a/orochi/templates/allauth/elements/panel.html b/orochi/templates/allauth/elements/panel.html new file mode 100644 index 00000000..979d67dc --- /dev/null +++ b/orochi/templates/allauth/elements/panel.html @@ -0,0 +1,17 @@ +{% load allauth %} +
    +
    +
    + {% slot title %} + {% endslot %} +
    + {% slot body %} + {% endslot %} +
    + {% if slots.actions %} + + {% endif %} +
    diff --git a/orochi/templates/allauth/elements/provider.html b/orochi/templates/allauth/elements/provider.html new file mode 100644 index 00000000..832638ad --- /dev/null +++ b/orochi/templates/allauth/elements/provider.html @@ -0,0 +1,4 @@ +{% load allauth %} +{{ attrs.name }} diff --git a/orochi/templates/allauth/elements/provider_list.html b/orochi/templates/allauth/elements/provider_list.html new file mode 100644 index 00000000..4a0d73ff --- /dev/null +++ b/orochi/templates/allauth/elements/provider_list.html @@ -0,0 +1,5 @@ +{% load allauth %} +
    + {% slot %} + {% endslot %} +
    diff --git a/orochi/templates/allauth/elements/table.html b/orochi/templates/allauth/elements/table.html new file mode 100644 index 00000000..178ae7df --- /dev/null +++ b/orochi/templates/allauth/elements/table.html @@ -0,0 +1,5 @@ +{% load allauth %} + + {% slot %} + {% endslot %} +
    diff --git a/orochi/templates/allauth/layouts/base.html b/orochi/templates/allauth/layouts/base.html new file mode 100644 index 00000000..4b65f8f6 --- /dev/null +++ b/orochi/templates/allauth/layouts/base.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% block title %}{% block head_title %}{% endblock head_title %}{% endblock title %} + +{% block fullpage %} +
    + {% block content %}{% endblock content %} +
    +{% endblock fullpage %} diff --git a/orochi/templates/allauth/layouts/entrance.html b/orochi/templates/allauth/layouts/entrance.html new file mode 100644 index 00000000..ea464d0d --- /dev/null +++ b/orochi/templates/allauth/layouts/entrance.html @@ -0,0 +1,26 @@ +{% extends "allauth/layouts/base.html" %} +{% load i18n allauth %} +{% block body %} +
    +
    +
    +
    + {% if messages %} + {% for message in messages %} + {% element alert level=message.tags %} + {% slot message %} + {{ message }} + {% endslot %} + {% endelement %} + {% endfor %} + {% endif %} +
    +
    + {% block content %}{% endblock %} +
    +
    +
    +
    +
    +
    +{% endblock %} diff --git a/orochi/templates/allauth/layouts/manage.html b/orochi/templates/allauth/layouts/manage.html new file mode 100644 index 00000000..7a53c1dc --- /dev/null +++ b/orochi/templates/allauth/layouts/manage.html @@ -0,0 +1,61 @@ +{% extends "allauth/layouts/base.html" %} +{% load allauth %} +{% block body %} +
    + +
    +
    + {% if messages %} +
    + {% for message in messages %} + {% element alert level=message.tags %} + {% slot message %} + {{ message }} + {% endslot %} + {% endelement %} + {% endfor %} +
    + {% endif %} + {% block content %}{% endblock %} +
    +
    +
    +{% endblock %} diff --git a/orochi/templates/base.html b/orochi/templates/base.html index d3650073..406e0a56 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -121,11 +121,46 @@
  • + {% url 'account_email' as email_url %} + {% if email_url %}
  • - - {% trans "Sign Out" %} + + {% trans "Change Email" %}
  • + {% endif %} + + {% url 'account_change_password' as change_password_url %} + {% if change_password_url %} +
  • + + {% trans "Change Password" %} + +
  • + {% endif %} + + {% url 'mfa_index' as mfa_url %} + {% if mfa_url %} +
  • + + {% trans "Two-Factor Authentication" %} + +
  • + {% endif %} + + {% url 'usersessions_list' as usersessions_list_url %} + {% if usersessions_list_url %} +
  • + + {% trans "Sessions" %} + +
  • + {% endif %} + + + {% trans "Sign Out" %} + +
    diff --git a/orochi/users/adapters.py b/orochi/users/adapters.py deleted file mode 100644 index 0d206fae..00000000 --- a/orochi/users/adapters.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Any - -from allauth.account.adapter import DefaultAccountAdapter -from allauth.socialaccount.adapter import DefaultSocialAccountAdapter -from django.conf import settings -from django.http import HttpRequest - - -class AccountAdapter(DefaultAccountAdapter): - def is_open_for_signup(self, request: HttpRequest): - return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) - - -class SocialAccountAdapter(DefaultSocialAccountAdapter): - def is_open_for_signup(self, request: HttpRequest, sociallogin: Any): - return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index c0fd6cf6..aa65b948 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -409,7 +409,7 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None, regipy_plugins=F has_file = False if params: for k, v in params.items(): - if k in ["yara_file", "yara_compiled_file", "yara_rules"] and ( + if k in ["yara_file", "yara_compiled_file", "yara_string"] and ( v is not None and v != "" ): has_file = True diff --git a/orochi/website/admin.py b/orochi/website/admin.py index c16a30b5..a368e208 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -1,4 +1,3 @@ -from allauth.socialaccount.models import SocialAccount, SocialApp, SocialToken from django.contrib import admin from django.contrib.auth.models import Group from django_admin_listfilter_dropdown.filters import RelatedDropdownFilter @@ -142,15 +141,12 @@ def get_form(self, request, obj=None, **kwargs): @admin.register(CustomRule) class CustomRulePluginAdmin(admin.ModelAdmin): - list_display = ("name", "path", "public", "user") - list_filter = ("public", "user") + list_display = ("name", "path", "public", "default", "user") + list_filter = ("public", "default", "user") search_fields = ("name",) admin.site.unregister(Group) -admin.site.unregister(SocialAccount) -admin.site.unregister(SocialToken) -admin.site.unregister(SocialApp) admin.site.unregister(TemporaryUploadedFile) admin.site.site_header = "Orochi Admin" diff --git a/orochi/ya/management/commands/generate_default_rule.py b/orochi/ya/management/commands/generate_default_rule.py index f9cb90bf..92b4710d 100644 --- a/orochi/ya/management/commands/generate_default_rule.py +++ b/orochi/ya/management/commands/generate_default_rule.py @@ -1,7 +1,7 @@ import os from pathlib import Path -import yara +import yara_x from django.conf import settings from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand, CommandError @@ -27,14 +27,19 @@ def handle(self, *args, **kwargs): } self.stdout.write(f"{len(rules_file.keys())} rules must be compiled") try: - rules = yara.compile(filepaths=rules_file) - except yara.Error as excp: + compiler = yara_x.Compiler() + for rulepath in rules_file.values(): + with open(rulepath, "r") as fp: + compiler.add_source(fp.read()) + rules = compiler.build() + except Exception as excp: self.stdout.write(self.style.ERROR(str(excp))) raise CommandError("Error compiling rules") from excp if os.path.exists(settings.DEFAULT_YARA_RULE_PATH): os.remove(settings.DEFAULT_YARA_RULE_PATH) - rules.save(settings.DEFAULT_YARA_RULE_PATH) + with open(settings.DEFAULT_YARA_RULE_PATH, "wb") as fo: + rules.serialize_into(fo) self.stdout.write(self.style.SUCCESS("Building completed!")) for user in get_user_model().objects.all(): diff --git a/orochi/ya/management/commands/rules_sync.py b/orochi/ya/management/commands/rules_sync.py index d1131b93..096ba0e1 100644 --- a/orochi/ya/management/commands/rules_sync.py +++ b/orochi/ya/management/commands/rules_sync.py @@ -4,7 +4,7 @@ import git import marko import requests -import yara +import yara_x from bs4 import BeautifulSoup from django.conf import settings from django.contrib.auth import get_user_model @@ -32,13 +32,14 @@ def compile_rule(self, item): compiled = False # TRY LOADING COMPILED, IF FAILS TRY LOAD try: - _ = yara.load(str(path)) + _ = yara_x.Rules.deserialize_from(str(path)) compiled = True self.stdout.write("\t\tCOMPILED") - except yara.Error: + except Exception: try: - _ = yara.compile(str(path), includes=False) - except yara.SyntaxError as e: + with open(str(path), "r") as fp: + _ = yara_x.compile(fp.read()) + except Exception as e: self.stdout.write(self.style.ERROR(f"\t\tCannot load rule {path}!")) self.stdout.write(f"\t\t\t{e}") rule.enabled = False diff --git a/requirements/base.txt b/requirements/base.txt index e5f24798..1ecd59f5 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,13 +1,13 @@ # https://github.com/stub42/pytz pytz==2024.1 # https://github.com/python-pillow/Pillow -Pillow==10.3.0 +Pillow==10.4.0 # https://github.com/hynek/argon2_cffi argon2-cffi==23.1.0 # https://github.com/evansd/whitenoise -whitenoise==6.6.0 +whitenoise==6.7.0 # https://github.com/andymccurdy/redis-py -redis==5.0.5 +redis==5.0.7 # https://github.com/redis/hiredis-py hiredis==2.3.2 # https://github.com/psycopg/psycopg2 @@ -20,17 +20,19 @@ python-magic==0.4.27 # Django # ------------------------------------------------------------------------------ # https://www.djangoproject.com/ -django==5.0.6 +django==5.0.7 # https://github.com/django/channels channels[daphne]==4.1.0 +# https://github.com/django/daphne +daphne==4.1.2 # https://github.com/django/channels_redis channels_redis==4.2.0 # https://github.com/joke2k/django-environ django-environ==0.11.2 # https://github.com/pennersr/django-allauth -django-allauth==0.63.3 +django-allauth[mfa]==0.63.6 # https://github.com/django-crispy-forms/django-crispy-forms -django-crispy-forms==2.1 +django-crispy-forms==2.3 # https://github.com/jazzband/django-redis django-redis==5.4.0 # https://gunicorn.org/ @@ -40,9 +42,9 @@ gunicorn==22.0.0 # Django Ninja # ------------------------------------------------------------------------------ # https://github.com/adamchainz/django-cors-headers -django-cors-headers==4.3.1 -# django-ninja -django-ninja==1.1.0 +django-cors-headers==4.4.0 +# https://github.com/vitalik/django-ninja +django-ninja==1.2.2 # Django tweak # ------------------------------------------------------------------------------ @@ -51,7 +53,7 @@ crispy-bootstrap5==2024.2 # https://github.com/fabiocaccamo/django-colorfield django-colorfield==0.11.0 # https://github.com/mbraak/django-file-form -django-file-form==3.6.0 +django-file-form==3.7.0 # https://github.com/django-guardian/django-guardian django-guardian==2.4.0 # https://github.com/jazzband/django-widget-tweaks @@ -73,15 +75,15 @@ luqum==0.13.0 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.5.2 +dask==2024.7.1 # https://github.com/dask/distributed -distributed==2024.5.2 +distributed==2024.7.1 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.0.8 # https://github.com/python-lz4/python-lz4 lz4==4.3.3 # https://numpy.org/ -numpy==1.26.4 +numpy==2.0.1 # https://github.com/cloudpipe/cloudpickle cloudpickle==3.0.0 # https://pypi.org/project/toolz/ @@ -95,19 +97,17 @@ pandas==2.2.2 # ------------------------------------------------------------------------------ # https://github.com/volatilityfoundation/ # volatility3==2.5.2 -# https://github.com/VirusTotal/yara-python -# yara-python==4.5.0 # https://github.com/Viicos/clamdpy clamdpy==0.1.0.post1 # https://github.com/VirusTotal/vt-py vt-py==0.18.2 # https://github.com/mkorman90/regipy/ -#regipy[full]==4.2.1 +#regipy[full]==4.3.0 regipy[full] @ git+https://github.com/dadokkio/regipy@6d11c7dc4ef864d13bc84bc23ef2ca80cb0a90f0 # http://www.capstone-engine.org/ capstone==5.0.1 # https://github.com/Julian/jsonschema -jsonschema==4.22.0 +jsonschema==4.23.0 # https://github.com/Legrandin/pycryptodome pycryptodome==3.20.0 # https://github.com/maxmind/GeoIP2-python @@ -118,7 +118,9 @@ geoip2==4.8.0 # https://github.com/gitpython-developers/GitPython GitPython==3.1.43 # https://github.com/frostming/marko -marko==2.0.3 +marko==2.1.2 +# https://github.com/VirusTotal/yara-x +yara_x==0.5.0 # symbols dwarf # ------------------------------------------------------------------------------ @@ -127,14 +129,14 @@ beautifulsoup4==4.12.3 # https://salsa.debian.org/python-debian-team/python-debian python-debian==0.1.49 # https://github.com/srossross/rpmfile -rpmfile==2.0.0 +rpmfile==2.1.0 # https://github.com/erocarrera/pefile pefile==2023.2.7 # misp export # ------------------------------------------------------------------------------ # https://github.com/MISP/PyMISP -pymisp==2.4.193 +pymisp==2.4.195 # ldap # ------------------------------------------------------------------------------ diff --git a/requirements/local.txt b/requirements/local.txt index 78b8a27e..7473047e 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -3,11 +3,11 @@ # Testing # ------------------------------------------------------------------------------ # https://github.com/python/mypy -mypy==1.10.0 +mypy==1.11.0 # https://github.com/typeddjango/django-stubs django-stubs==5.0.2 # https://github.com/pytest-dev/pytest -pytest==8.1.1 +pytest==8.2.2 # https://github.com/Frozenball/pytest-sugar pytest-sugar==1.0.0 @@ -18,7 +18,7 @@ flake8==7.0.0 # https://github.com/gforcada/flake8-isort flake8-isort==6.1.1 # https://github.com/nedbat/coveragepy -coverage==7.5.3 +coverage==7.5.4 # https://github.com/ambv/black black==24.4.2 # https://github.com/PyCQA/pylint-django @@ -31,7 +31,7 @@ pre-commit==3.7.1 # https://github.com/FactoryBoy/factory_boy factory-boy==3.3.0 # https://github.com/jazzband/django-debug-toolbar -django-debug-toolbar==4.4.2 +django-debug-toolbar==4.4.6 # https://github.com/django-extensions/django-extensions django-extensions==3.2.3 # https://github.com/nedbat/django_coverage_plugin diff --git a/setup.cfg b/setup.cfg index 4e29b439..f0bb6ed0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,7 +7,7 @@ max-line-length = 120 exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules [mypy] -python_version = 3.8 +python_version = 3.12 check_untyped_defs = True ignore_missing_imports = True warn_unused_ignores = True From 58ac0781b7da73ea8fda1036b208dd45b1bdc650 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 30 Jul 2024 15:57:36 +0200 Subject: [PATCH 56/84] rule filter fix --- .env.sample | 3 +++ docker-compose.yml | 15 +++++++-------- orochi/ya/schema.py | 6 +++--- orochi/ya/views.py | 20 +++++++++++++++----- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.env.sample b/.env.sample index 0fd25230..91d77cd1 100644 --- a/.env.sample +++ b/.env.sample @@ -1 +1,4 @@ VERSION=latest +ELASTIC_VERSION=8.13.0 +REDIS_VERSION=6.2.5 +POSTGRES_VERSION=16.2 diff --git a/docker-compose.yml b/docker-compose.yml index 73be38e5..ef421cc7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,14 +3,12 @@ version: "3" volumes: local_postgres_data: {} local_postgres_data_backups: {} + elasticsearch_data: {} media_path: {} symbols_path: {} plugin_path: {} cache_path: {} yara_path: {} - data01: - driver: local - services: nginx: @@ -19,6 +17,7 @@ services: dockerfile: ./compose/local/nginx/Dockerfile image: ghcr.io/ldo-cert/orochi_nginx:${VERSION:-latest} container_name: orochi_nginx + restart: always depends_on: - django_asgi - django_wsgi @@ -91,7 +90,7 @@ services: command: daphne -b 0.0.0.0 -p 9000 config.asgi:application postgres: - image: postgres:16.2 + image: postgres:${POSTGRES_VERSION:-16.2} container_name: orochi_postgres hostname: postgres restart: always @@ -113,7 +112,7 @@ services: - "8025:8025" redis: - image: redis:6.2.5 + image: redis:${REDIS_VERSION:-6.2.5} container_name: orochi_redis hostname: redis restart: always @@ -121,7 +120,7 @@ services: - "6379:6379" es01: - image: elasticsearch:8.13.0 + image: elasticsearch:${ELASTIC_VERSION:-8.13.0} container_name: orochi_es01 environment: - discovery.type=single-node @@ -139,12 +138,12 @@ services: soft: -1 hard: -1 volumes: - - data01:/usr/share/elasticsearch/data + - elasticsearch_data:/usr/share/elasticsearch/data ports: - 9200:9200 kib01: - image: kibana:8.13.0 + image: kibana:${ELASTIC_VERSION:-8.13.0} container_name: orochi_kib01 ports: - 5601:5601 diff --git a/orochi/ya/schema.py b/orochi/ya/schema.py index 135f24cf..3215859b 100644 --- a/orochi/ya/schema.py +++ b/orochi/ya/schema.py @@ -55,7 +55,7 @@ def add_document(self, rulepath, ruleset, description, rule_id): def remove_document(self, rule_id): self.es_client.delete(index=self.index_name, id=rule_id) - def search(self, query, sort, start, length): + def search(self, query, sort): schema_analizer = SchemaAnalyzer(self.schema) message_es_builder = ElasticsearchQueryBuilder( **schema_analizer.query_builder_options(), @@ -66,7 +66,7 @@ def search(self, query, sort, start, length): query = {"query": message_es_builder(tree)} s = Search(index=self.index_name).using(self.es_client).sort(sort) s = ( - s.update_from_dict(query)[start:length] + s.update_from_dict(query) .highlight("path", fragment_size=40) .highlight("ruleset", fragment_size=40) .highlight("rule", fragment_size=40) @@ -92,6 +92,6 @@ def search(self, query, sort, start, length): parts[:5], ] ) - return results, response.hits.total.value + return results except (ParseSyntaxError, RequestError): return [], 0 diff --git a/orochi/ya/views.py b/orochi/ya/views.py index 22500d32..518ddd0b 100644 --- a/orochi/ya/views.py +++ b/orochi/ya/views.py @@ -44,6 +44,7 @@ def list_rules(request): """ Ajax rules return for datatables """ + draw = request.GET.get("draw") start = int(request.GET.get("start")) length = int(request.GET.get("length")) search = request.GET.get("search[value]") @@ -58,26 +59,35 @@ def list_rules(request): .filter(enabled=True) ) rules_id = [x.id for x in rules] + total = rules.count() if search: sort = ["id", "ruleset", "path"][sort_column] if sort_order == "desc": sort = f"-{sort}" rule_index = RuleIndex() - results, count = rule_index.search(search, sort, start, start + length) + try: + results = rule_index.search(search, sort) + filtered_data = [x for x in results if int(x[0]) in rules_id][ + start : start + length + ] + except Exception as excp: + # partial query error. Eg: "foobar AND" + filtered_data = [] return_data = { - "recordsTotal": rules.count(), - "recordsFiltered": count, - "data": [x for x in results if int(x[0]) in rules_id], + "draw": draw, + "recordsTotal": total, + "recordsFiltered": len(filtered_data), + "data": filtered_data, } return JsonResponse(return_data) sort = ["pk", "ruleset__name", "path"][sort_column] if sort_order == "desc": sort = f"-{sort}" - results = rules data = rules.order_by(sort)[start : start + length] return_data = { + "draw": draw, "recordsTotal": rules.count(), "recordsFiltered": rules.count(), "data": [ From 3db9ca2f778ffa3a187e49ef204007a0941bb2d0 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 31 Jul 2024 16:57:33 +0200 Subject: [PATCH 57/84] extra settings --- compose/local/nginx/conf/default.conf | 5 ++ config/settings/base.py | 62 ++++++++++++++---- docker-compose.yml | 1 + orochi/api/routers/customrules.py | 4 +- orochi/api/routers/rules.py | 4 +- orochi/templates/account/login.html | 65 +++++++++++++++++++ orochi/utils/download_symbols.py | 6 +- orochi/utils/plugin_install.py | 7 +- orochi/utils/volatility_dask_elk.py | 5 +- .../management/commands/symbols_sync.py | 7 +- orochi/website/middleware.py | 7 ++ orochi/website/views.py | 19 +++--- .../commands/generate_default_rule.py | 13 ++-- orochi/ya/management/commands/rules_sync.py | 19 +++--- orochi/ya/views.py | 4 +- requirements/base.txt | 4 +- 16 files changed, 174 insertions(+), 58 deletions(-) create mode 100644 orochi/templates/account/login.html diff --git a/compose/local/nginx/conf/default.conf b/compose/local/nginx/conf/default.conf index ae114825..7447a282 100644 --- a/compose/local/nginx/conf/default.conf +++ b/compose/local/nginx/conf/default.conf @@ -42,6 +42,11 @@ server { client_max_body_size 1000M; } + location ^~ /media/ { + autoindex on; + alias /usr/share/nginx/html/media/; + } + location /ws/notify/ { proxy_pass http://django_asgi; proxy_http_version 1.1; diff --git a/config/settings/base.py b/config/settings/base.py index 796b9f91..3c50489e 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -69,6 +69,7 @@ "widget_tweaks", "django_admin_listfilter_dropdown", "django_admin_multiple_choice_list_filter", + "extra_settings", ] LOCAL_APPS = [ @@ -288,31 +289,64 @@ # django-cors-headers - https://github.com/adamchainz/django-cors-headers#setup CORS_URLS_REGEX = r"^/api/.*$" CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS") -# OROCHI CONFIGURATIONS -# ------------------------------------------------------------------------------- -# elastic windows size to increase number of returned results -MAX_ELASTIC_WINDOWS_SIZE = env("MAX_ELASTIC_WINDOWS_SIZE") -# path of the default yara path -DEFAULT_YARA_RULE_PATH = env("DEFAULT_YARA_RULE_PATH") -# thread number for multiprocess operation -THREAD_NO = env.int("THREAD_NO") -# online url for awesome readme file -AWESOME_PATH = env("AWESOME_PATH") + +# OROCHI EXTRA_SETTINGS +# ------------------------------------------------------------------------------ +EXTRA_SETTINGS_ADMIN_APP = "extra_settings" +EXTRA_SETTINGS_CACHE_NAME = "extra_settings" +EXTRA_SETTINGS_IMAGE_UPLOAD_TO = "images" + +EXTRA_SETTINGS_DEFAULTS = [ + { + "description": "Elastic windows size to increase number of returned results", + "name": "MAX_ELASTIC_WINDOWS_SIZE", + "type": "string", + "value": env("MAX_ELASTIC_WINDOWS_SIZE"), + }, + { + "description": "path of the default yara path. When changed you must rebuild it.", + "name": "DEFAULT_YARA_RULE_PATH", + "type": "string", + "value": env("DEFAULT_YARA_RULE_PATH"), + }, + { + "description": "Thread number for multiprocess operation", + "name": "THREAD_NO", + "type": "int", + "value": env.int("THREAD_NO"), + }, + { + "description": "Online url for awesome readme file", + "name": "AWESOME_PATH", + "type": "string", + "value": env("AWESOME_PATH"), + }, + { + "description": "Online path of volatility symbols", + "name": "VOLATILITY_SYMBOL_DOWNLOAD_PATH", + "type": "string", + "value": env("VOLATILITY_SYMBOL_DOWNLOAD_PATH"), + }, + { + "description": "Path for custom login logo", + "name": "CUSTOM_LOGO", + "type": "image", + "value": "logo.png", + }, +] + # local path for yara folder LOCAL_YARA_PATH = env("LOCAL_YARA_PATH") -# extension valid to be considered as yara file +# Valid yara file exts YARA_EXT = [".yar", ".yara", ".rule"] # indexes name for rules RULES_INDEX = "rules" -RULES_ANALYSIS_INDEX = "rules_analysis" # local path of volatility folder VOLATILITY_SYMBOL_PATH = "/src/volatility3/volatility3/symbols" VOLATILITY_PLUGIN_PATH = "/src/volatility3/volatility3/plugins/custom" # local path of dwarg2json executable DWARF2JSON = "/dwarf2json/./dwarf2json" -# online path of volatility symbols -VOLATILITY_SYMBOL_DOWNLOAD_PATH = env("VOLATILITY_SYMBOL_DOWNLOAD_PATH") # path of a remote folder with already uploaded files LOCAL_UPLOAD_PATH = env("LOCAL_UPLOAD_PATH") # Regipy plugins diff --git a/docker-compose.yml b/docker-compose.yml index ef421cc7..5cbf1c90 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,7 @@ services: - django_wsgi volumes: - ./compose/local/nginx/conf:/etc/nginx/conf.d + - media_path:/usr/share/nginx/html/media/ ports: - "80:80" - "443:443" diff --git a/orochi/api/routers/customrules.py b/orochi/api/routers/customrules.py index 5ca4ab0f..6af28ee7 100644 --- a/orochi/api/routers/customrules.py +++ b/orochi/api/routers/customrules.py @@ -1,9 +1,9 @@ import os import shutil -from django.conf import settings from django.db.models import Q from django.http import HttpResponse +from extra_settings.models import Setting from ninja import Router from ninja.security import django_auth @@ -53,7 +53,7 @@ def default_rule(request, id: int): rule.save() return 200, {"message": f"Rule {name} set as default."} # Make a copy - user_path = f"{settings.LOCAL_YARA_PATH}/{request.user.username}-Ruleset" + user_path = f"{Setting.get('LOCAL_YARA_PATH')}/{request.user.username}-Ruleset" os.makedirs(user_path, exist_ok=True) new_path = f"{user_path}/{rule.name}" filename, extension = os.path.splitext(new_path) diff --git a/orochi/api/routers/rules.py b/orochi/api/routers/rules.py index 0e3cc865..e5aa8b42 100644 --- a/orochi/api/routers/rules.py +++ b/orochi/api/routers/rules.py @@ -2,9 +2,9 @@ from pathlib import Path import yara_x -from django.conf import settings from django.http import HttpResponse from django.shortcuts import get_object_or_404 +from extra_settings.models import Setting from ninja import Router from ninja.security import django_auth @@ -47,7 +47,7 @@ def edit_rule(request, id: int, data: RuleEditInSchena): f.write(data.text) return 200, {"message": f"Rule {name} updated."} ruleset = get_object_or_404(Ruleset, user=request.user) - user_path = f"{settings.LOCAL_YARA_PATH}/{request.user.username}-Ruleset" + user_path = f"{Setting.get('LOCAL_YARA_PATH')}/{request.user.username}-Ruleset" os.makedirs(user_path, exist_ok=True) rule.pk = None rule.ruleset = ruleset diff --git a/orochi/templates/account/login.html b/orochi/templates/account/login.html new file mode 100644 index 00000000..c2a106bd --- /dev/null +++ b/orochi/templates/account/login.html @@ -0,0 +1,65 @@ +{% extends "account/base_entrance.html" %} +{% load i18n %} +{% load static %} +{% load allauth account %} +{% block head_title %} + {% trans "Sign In" %} +{% endblock head_title %} +{% block content %} + {% element h1 %} + {% trans "Sign In" %} + {% endelement %} + {% element p %} + + {% endelement %} + {% if not SOCIALACCOUNT_ONLY %} + {% setvar link %} + + {% endsetvar %} + {% setvar end_link %} + + {% endsetvar %} + {% element p %} + {% blocktranslate %}If you have not created an account yet, then please {{ link }}sign up{{ end_link }} first.{% endblocktranslate %} + {% endelement %} + {% url 'account_login' as login_url %} + {% element form form=form method="post" action=login_url tags="entrance,login" %} + {% slot body %} + {% csrf_token %} + {% element fields form=form unlabeled=True %} + {% endelement %} + {{ redirect_field }} + {% endslot %} + {% slot actions %} + {% element button type="submit" tags="prominent,login" %} + {% trans "Sign In" %} + {% endelement %} + {% endslot %} + {% endelement %} + {% endif %} + {% if LOGIN_BY_CODE_ENABLED or PASSKEY_LOGIN_ENABLED %} + {% element hr %} + {% endelement %} + {% element button_group vertical=True %} + {% if PASSKEY_LOGIN_ENABLED %} + {% element button type="submit" form="mfa_login" id="passkey_login" tags="prominent,login,outline,primary" %} + {% trans "Sign in with a passkey" %} + {% endelement %} + {% endif %} + {% if LOGIN_BY_CODE_ENABLED %} + {% element button href=request_login_code_url tags="prominent,login,outline,primary" %} + {% trans "Mail me a sign-in code" %} + {% endelement %} + {% endif %} + {% endelement %} + {% endif %} + {% if SOCIALACCOUNT_ENABLED %} + {% include "socialaccount/snippets/login.html" with page_layout="entrance" %} + {% endif %} +{% endblock content %} +{% block extra_body %} + {{ block.super }} + {% if PASSKEY_LOGIN_ENABLED %} + {% include "mfa/webauthn/snippets/login_script.html" with button_id="passkey_login" %} + {% endif %} +{% endblock %} diff --git a/orochi/utils/download_symbols.py b/orochi/utils/download_symbols.py index d5a83b0e..7fb7479a 100644 --- a/orochi/utils/download_symbols.py +++ b/orochi/utils/download_symbols.py @@ -9,7 +9,7 @@ import requests import rpmfile from debian import debfile -from django.conf import settings +from extra_settings.models import Setting from pefile import PE from volatility3.framework.contexts import Context from volatility3.framework.symbols.windows.pdbconv import PdbReader, PdbRetreiver @@ -19,7 +19,7 @@ class Downloader: def __init__(self, file_list: List[str] = None, url_list: List[str] = None) -> None: self.url_list = url_list if url_list is not None else [] self.file_list = file_list if file_list is not None else [] - self.down_path = f"{settings.VOLATILITY_SYMBOL_PATH}/added/" + self.down_path = f"{Setting.get('VOLATILITY_SYMBOL_PATH')}/added/" def download_list(self): """Download and process files from web urls [Linux]""" @@ -69,7 +69,7 @@ def process_files(self, named_files: Dict[str, str]): if value is None: print(f"FAILURE: None encountered for {i}") return - args = [settings.DWARF2JSON, "linux"] + args = [Setting.get("DWARF2JSON"), "linux"] output_filename = "unknown-kernel.json" for named_file, value_ in named_files.items(): basename, _ = os.path.splitext(named_file) diff --git a/orochi/utils/plugin_install.py b/orochi/utils/plugin_install.py index d88ee429..6f732ca7 100644 --- a/orochi/utils/plugin_install.py +++ b/orochi/utils/plugin_install.py @@ -5,10 +5,9 @@ import zipfile from pathlib import Path -from distributed import get_client -from django.conf import settings - import volatility3.plugins +from distributed import get_client +from extra_settings.models import Setting from volatility3 import framework from volatility3.framework import contexts @@ -26,7 +25,7 @@ def install_process(bash_script, reqs_script, tmp_folder): bash_script = None reqs_script = False py_names = [] - plugin_folder = Path(settings.VOLATILITY_PLUGIN_PATH) + plugin_folder = Path(Setting.get("VOLATILITY_PLUGIN_PATH")) tmp_folder = plugin_folder / str(uuid.uuid4()) os.mkdir(tmp_folder) with zipfile.ZipFile(plugin_path, "r") as f: diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index aa65b948..b274b3dd 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -28,6 +28,7 @@ from django.conf import settings from elasticsearch import Elasticsearch, helpers from elasticsearch_dsl import Search +from extra_settings.models import Setting from regipy.exceptions import ( NoRegistrySubkeysException, RegistryKeyNotFoundException, @@ -534,7 +535,9 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None, regipy_plugins=F es.indices.put_settings( index=f"{dump_obj.index}_{plugin_obj.name.lower()}", body={ - "index": {"max_result_window": settings.MAX_ELASTIC_WINDOWS_SIZE} + "index": { + "max_result_window": Setting.get("MAX_ELASTIC_WINDOWS_SIZE") + } }, ) diff --git a/orochi/website/management/commands/symbols_sync.py b/orochi/website/management/commands/symbols_sync.py index 6c9eb278..78e60ddd 100644 --- a/orochi/website/management/commands/symbols_sync.py +++ b/orochi/website/management/commands/symbols_sync.py @@ -6,9 +6,8 @@ import requests import urllib3 -from django.conf import settings from django.core.management.base import BaseCommand - +from extra_settings.models import Setting from volatility3 import framework urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) @@ -19,8 +18,8 @@ class Command(BaseCommand): def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) - self.local_path = Path(settings.VOLATILITY_SYMBOL_PATH) - self.online_path = settings.VOLATILITY_SYMBOL_DOWNLOAD_PATH + self.local_path = Path(Setting.get("VOLATILITY_SYMBOL_PATH")) + self.online_path = Setting.get("VOLATILITY_SYMBOL_DOWNLOAD_PATH") if os.environ.get("http_proxy", None) or os.environ.get("https_proxy", None): self.proxies = { "http": os.environ.get("http_proxy", None), diff --git a/orochi/website/middleware.py b/orochi/website/middleware.py index 168fef2e..b991f3ef 100644 --- a/orochi/website/middleware.py +++ b/orochi/website/middleware.py @@ -1,6 +1,7 @@ from operator import itemgetter from django.urls import reverse +from extra_settings.models import Setting from guardian.shortcuts import get_objects_for_user from orochi.website.defaults import ( @@ -49,4 +50,10 @@ def process_template_response(self, request, response): response.context_data["news"] = news bookmarks = Bookmark.objects.filter(user=request.user, star=True) response.context_data["bookmarks"] = bookmarks + + # Default logo or pick new one from extra settings + if logo := Setting.get("CUSTOM_LOGO"): + response.context_data["logo"] = logo.url + else: + response.context_data["logo"] = "/static/images/logo.png" return response diff --git a/orochi/website/views.py b/orochi/website/views.py index 7ffa95c6..4bfe4ed3 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -33,9 +33,11 @@ from django.views.decorators.http import require_http_methods from elasticsearch import Elasticsearch from elasticsearch_dsl import Search +from extra_settings.models import Setting from guardian.shortcuts import assign_perm, get_objects_for_user, get_perms, remove_perm from pymisp import MISPEvent, MISPObject, PyMISP from pymisp.tools import FileObject +from volatility3.framework import automagic, contexts from orochi.utils.download_symbols import Downloader from orochi.utils.volatility_dask_elk import ( @@ -76,7 +78,6 @@ Service, UserPlugin, ) -from volatility3.framework import automagic, contexts COLOR_TEMPLATE = """ Date: Mon, 5 Aug 2024 19:42:37 +0200 Subject: [PATCH 58/84] #1082 --- config/settings/base.py | 4 ++ orochi/templates/admin/dump_intermediate.html | 12 ++++ orochi/utils/volatility_dask_elk.py | 50 ++++++++------- orochi/website/admin.py | 64 ++++++++++++++++++- orochi/website/forms.py | 16 +++++ 5 files changed, 123 insertions(+), 23 deletions(-) create mode 100644 orochi/templates/admin/dump_intermediate.html diff --git a/config/settings/base.py b/config/settings/base.py index 3c50489e..f5449e5e 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -251,6 +251,10 @@ ACCOUNT_EMAIL_VERIFICATION = "optional" ACCOUNT_ADAPTER = "allauth.account.adapter.DefaultAccountAdapter" +MFA_SUPPORTED_TYPES = ["totp", "webauthn"] +MFA_PASSKEY_LOGIN_ENABLED = True +MFA_WEBAUTHN_ALLOW_INSECURE_ORIGIN = True + # Elasticsearch # ------------------------------------------------------------------------------- ELASTICSEARCH_URL = env("ELASTICSEARCH_URL") diff --git a/orochi/templates/admin/dump_intermediate.html b/orochi/templates/admin/dump_intermediate.html new file mode 100644 index 00000000..e44daba6 --- /dev/null +++ b/orochi/templates/admin/dump_intermediate.html @@ -0,0 +1,12 @@ +{% extends "admin/base_site.html" %} + +{% block content %} +
    + {% csrf_token %} +

    Selected dumps:

    +
      {{ items|unordered_list }}
    + {{ form }} + + + +{% endblock %} diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index b274b3dd..0b863093 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -26,6 +26,7 @@ from clamdpy import ClamdUnixSocket from distributed import fire_and_forget, get_client, rejoin, secede from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist from elasticsearch import Elasticsearch, helpers from elasticsearch_dsl import Search from extra_settings.models import Setting @@ -828,30 +829,35 @@ def unzip_then_run(dump_pk, user_pk, password, restart, move): # check symbols using banners if dump.operating_system in ("Linux", "Mac"): - if banner := dump.result_set.get(plugin__name="banners.Banners"): - banner.result = RESULT_STATUS_RUNNING - banner.save() - logging.info(f"[dump {dump_pk}] Running banners plugin") - run_plugin(dump, banner.plugin) - time.sleep(1) - if banner_result := get_banner(banner): - dump.banner = banner_result.strip("\"'") - logging.error( - f"[dump {dump_pk}] guessed banner '{dump.banner}'" - ) - dump.save() + try: + if banner := dump.result_set.get(plugin__name="banners.Banners"): + banner.result = RESULT_STATUS_RUNNING + banner.save() + logging.info(f"[dump {dump_pk}] Running banners plugin") + run_plugin(dump, banner.plugin) + time.sleep(1) + if banner_result := get_banner(banner): + dump.banner = banner_result.strip("\"'") + logging.error( + f"[dump {dump_pk}] guessed banner '{dump.banner}'" + ) + dump.save() + except ObjectDoesNotExist: + logging.error(f"[dump {dump_pk}] Banner plugin missing") elif dump.operating_system == "Windows": - regipy = dump.result_set.get( - plugin__name="windows.registry.hivelist.HiveList" - ) - logging.info(f"[dump {dump_pk}] Running regipy plugins") - # run_plugin(dump, regipy.plugin, regipy_plugins=True) - dask_client = get_client() - fire_and_forget( - dask_client.submit( - run_plugin, dump, regipy.plugin, regipy_plugins=True + try: + regipy = dump.result_set.get( + plugin__name="windows.registry.hivelist.HiveList" ) - ) + logging.info(f"[dump {dump_pk}] Running regipy plugins") + dask_client = get_client() + fire_and_forget( + dask_client.submit( + run_plugin, dump, regipy.plugin, regipy_plugins=True + ) + ) + except ObjectDoesNotExist: + logging.error(f"[dump {dump_pk}] HiveList plugin missing") if restart or check_runnable(dump.pk, dump.operating_system, dump.banner): dask_client = get_client() diff --git a/orochi/website/admin.py b/orochi/website/admin.py index a368e208..d0a5befd 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -1,5 +1,8 @@ from django.contrib import admin +from django.contrib.auth import get_user_model from django.contrib.auth.models import Group +from django.http import HttpResponseRedirect +from django.shortcuts import render from django_admin_listfilter_dropdown.filters import RelatedDropdownFilter from django_admin_multiple_choice_list_filter.list_filters import ( MultipleChoiceListFilter, @@ -7,9 +10,14 @@ from django_file_form.model_admin import FileFormAdmin from django_file_form.models import TemporaryUploadedFile from guardian.admin import GuardedModelAdmin +from guardian.shortcuts import assign_perm, get_objects_for_user, get_perms, remove_perm from orochi.website.defaults import RESULT -from orochi.website.forms import PluginCreateAdminForm, PluginEditAdminForm +from orochi.website.forms import ( + PluginCreateAdminForm, + PluginEditAdminForm, + UserListForm, +) from orochi.website.models import ( Bookmark, CustomRule, @@ -64,11 +72,65 @@ class ResultAdmin(admin.ModelAdmin): @admin.register(Dump) class DumpAdmin(GuardedModelAdmin): + actions = ["assign_to_users", "remove_from_users"] list_display = ("name", "author", "index", "status") search_fields = ["author__name", "name", "index"] list_filter = ("author", "status", "created_at") exclude = ("suggested_symbols_path", "regipy_plugins", "banner") + def assign_to_users(self, request, queryset): + if "apply" in request.POST: + users = request.POST.getlist("authorized_users") + for item in queryset: + for user_pk in users: + user = get_user_model().objects.get(pk=user_pk) + assign_perm("can_see", user, item) + self.message_user( + request, f"{len(queryset)} dumps added to {len(users)} users" + ) + return HttpResponseRedirect(request.get_full_path()) + form = UserListForm( + initial={"_selected_action": queryset.values_list("id", flat=True)} + ) + return render( + request, + "admin/dump_intermediate.html", + context={ + "items": queryset, + "form": form, + "title": "Assign dumps to users", + "action": "assign_to_users", + }, + ) + + def remove_from_users(self, request, queryset): + if "apply" in request.POST: + users = request.POST.getlist("authorized_users") + for item in queryset: + for user_pk in users: + user = get_user_model().objects.get(pk=user_pk) + remove_perm("can_see", user, item) + self.message_user( + request, f"{len(queryset)} dumps removed from {len(users)} users" + ) + return HttpResponseRedirect(request.get_full_path()) + form = UserListForm( + initial={"_selected_action": queryset.values_list("id", flat=True)} + ) + return render( + request, + "admin/dump_intermediate.html", + context={ + "items": queryset, + "form": form, + "title": "Remove dumps from users", + "action": "remove_from_users", + }, + ) + + assign_to_users.short_description = "Assign dump to users" + remove_from_users.short_description = "Remove dumps from users" + def get_queryset(self, request): return super(DumpAdmin, self).get_queryset(request).prefetch_related("plugins") diff --git a/orochi/website/forms.py b/orochi/website/forms.py index 3d257156..f32cb6cc 100644 --- a/orochi/website/forms.py +++ b/orochi/website/forms.py @@ -206,6 +206,22 @@ class Meta: } +###################################### +# ADMIN USERLIST +###################################### +class UserListForm(forms.Form): + _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) + authorized_users = forms.TypedMultipleChoiceField( + required=False, + ) + + def __init__(self, *args, **kwargs): + super(UserListForm, self).__init__(*args, **kwargs) + self.fields["authorized_users"].choices = [ + (x.pk, x.username) for x in get_user_model().objects.all() + ] + + ###################################### # CREATE PLUGIN FROM ADMIN ###################################### From 1323e48529b3249efbb37f619c814d3f73649e72 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Mon, 5 Aug 2024 19:53:12 +0200 Subject: [PATCH 59/84] #1082 --- orochi/website/admin.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/orochi/website/admin.py b/orochi/website/admin.py index d0a5befd..b9dad8d9 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -73,11 +73,21 @@ class ResultAdmin(admin.ModelAdmin): @admin.register(Dump) class DumpAdmin(GuardedModelAdmin): actions = ["assign_to_users", "remove_from_users"] - list_display = ("name", "author", "index", "status") + list_display = ("name", "author", "index", "status", "get_auth_users") search_fields = ["author__name", "name", "index"] list_filter = ("author", "status", "created_at") exclude = ("suggested_symbols_path", "regipy_plugins", "banner") + def get_auth_users(self, obj): + auth_users = [ + user.username + for user in get_user_model().objects.all() + if "can_see" in get_perms(user, obj) + ] + return ", ".join(auth_users) + + get_auth_users.short_description = "Authorized Users" + def assign_to_users(self, request, queryset): if "apply" in request.POST: users = request.POST.getlist("authorized_users") From d92cf5a005d4654ed67c53c0b75043e0feff01ca Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 6 Aug 2024 13:28:07 +0200 Subject: [PATCH 60/84] add bodyfile support for timeliner --- compose/local/__init__.py | 21 +++++++-------------- compose/local/dask/Dockerfile | 2 +- compose/local/django/Dockerfile | 2 +- orochi/templates/website/partial_note.html | 9 +++++++-- orochi/utils/volatility_dask_elk.py | 7 +++++++ orochi/website/views.py | 12 ++++++++++++ 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/compose/local/__init__.py b/compose/local/__init__.py index 4e86eacf..1da162dd 100644 --- a/compose/local/__init__.py +++ b/compose/local/__init__.py @@ -14,6 +14,13 @@ import volatility3.framework.constants.linux import volatility3.framework.constants.windows +from volatility3.framework.constants._version import ( + PACKAGE_VERSION, + VERSION_MAJOR, + VERSION_MINOR, + VERSION_PATCH, + VERSION_SUFFIX, +) PLUGINS_PATH = [ os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "plugins")), @@ -42,20 +49,6 @@ BANG = "!" """Constant used to delimit table names from type names when referring to a symbol""" -# We use the SemVer 2.0.0 versioning scheme -VERSION_MAJOR = 2 # Number of releases of the library with a breaking change -VERSION_MINOR = 7 # Number of changes that only add to the interface -VERSION_PATCH = 1 # Number of changes that do not change the interface -VERSION_SUFFIX = "" - -# TODO: At version 2.0.0, remove the symbol_shift feature - -PACKAGE_VERSION = ( - ".".join([str(x) for x in [VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH]]) - + VERSION_SUFFIX -) -"""The canonical version of the volatility3 package""" - AUTOMAGIC_CONFIG_PATH = "automagic" """The root section within the context configuration for automagic values""" diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 41c8cab2..d94912b2 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -27,7 +27,7 @@ RUN freshclam # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@dc8dc9b078d42e41698ff93f2e65c5ee99aa2172#egg=volatility3 \ +RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@f740146f692ba288f376a939b24b1c1a8f7cf5e2#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 75741ad1..aa1f5d46 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -45,7 +45,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@dc8dc9b078d42e41698ff93f2e65c5ee99aa2172#egg=volatility3 \ +RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@f740146f692ba288f376a939b24b1c1a8f7cf5e2#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/orochi/templates/website/partial_note.html b/orochi/templates/website/partial_note.html index e5dc952b..108358d8 100644 --- a/orochi/templates/website/partial_note.html +++ b/orochi/templates/website/partial_note.html @@ -13,6 +13,11 @@

    Rerun {% endif %} + {% if bodyfile %} + + BodyFile + + {% endif %}

    {% for item in note %} @@ -50,9 +55,9 @@

    {% if item.description %} btn-log" data-log="{{item.description}}">{{item.result}} - {% else %} + {% else %} ">{{item.result}} - {% endif %} + {% endif %}

    diff --git a/orochi/utils/volatility_dask_elk.py b/orochi/utils/volatility_dask_elk.py index 0b863093..0aaddf81 100644 --- a/orochi/utils/volatility_dask_elk.py +++ b/orochi/utils/volatility_dask_elk.py @@ -361,6 +361,13 @@ def run_plugin(dump_obj, plugin_obj, params=None, user_pk=None, regipy_plugins=F # LOCAL DUMPS REQUIRES FILES - Also regipy plugins local_dump = plugin_obj.local_dump or regipy_plugins + # Timeliner can create a body-file if required + if ( + plugin_obj.name == "timeliner.Timeliner" + and params.get("create-bodyfile") == True + ): + local_dump = True + # ADD PARAMETERS, AND IF LOCAL DUMP ENABLE ADD DUMP TRUE BY DEFAULT plugin_config_path = interfaces.configuration.path_join( base_config_path, plugin.__name__ diff --git a/orochi/website/views.py b/orochi/website/views.py index 4bfe4ed3..cfac3a4e 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -464,6 +464,17 @@ def analysis(request): or os.path.exists("/maxmind/GeoLite2-City.mmdb") or os.path.exists("/maxmind/GeoLite2-Country.mmdb") ) + + bodyfile_path = ( + Path(res.dump.upload.path).parent + / "timeliner.Timeliner/volatility.body" + ) + bodyfile = ( + bodyfile_path + if plugin.name == "timeliner.Timeliner" and bodyfile_path.exists() + else None + ) + return render( request, "website/partial_analysis.html", @@ -472,6 +483,7 @@ def analysis(request): "columns": columns, "plugin": plugin.name, "maxmind": maxmind, + "bodyfile": bodyfile, }, ) From 9cb16a085b0bc51c02ac991801e3fe9dd0fa1780 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 6 Aug 2024 14:34:42 +0200 Subject: [PATCH 61/84] plot bodyfile chart --- .../templates/website/partial_analysis.html | 18 +++++ orochi/utils/timeliner.py | 76 +++++++++++++++++++ orochi/website/views.py | 20 ++--- requirements/base.txt | 4 + 4 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 orochi/utils/timeliner.py diff --git a/orochi/templates/website/partial_analysis.html b/orochi/templates/website/partial_analysis.html index 025c7eb5..a9b290a5 100644 --- a/orochi/templates/website/partial_analysis.html +++ b/orochi/templates/website/partial_analysis.html @@ -1,6 +1,24 @@ {% load custom_tags %} {% include "website/partial_note.html" %} +{% if bodyfile_chart %} +
    +
    +

    + +

    +
    +
    + {{ bodyfile_chart|safe }} +
    +
    +
    +
    +{% endif %} + diff --git a/orochi/utils/timeliner.py b/orochi/utils/timeliner.py new file mode 100644 index 00000000..c1a4bb45 --- /dev/null +++ b/orochi/utils/timeliner.py @@ -0,0 +1,76 @@ +from datetime import datetime + +import pandas as pd +import plotly.express as px +from django.views.generic.base import TemplateView + + +def parse_body_line(line): + parts = line.strip("|").split("|") # Split the line using '|' as the delimiter + plugin_description = parts[0].strip() + if "-" in plugin_description: + # Split on the first hyphen + plugin, description = plugin_description.split("-", 1) + plugin = plugin.strip() + description = description.strip() + else: + plugin = "Unknown" + description = plugin_description + try: + timestamp = int(parts[-1].strip()) + date = datetime.utcfromtimestamp(timestamp) if timestamp > 0 else None + except ValueError: + date = None + return {"Plugin": plugin, "Description": description, "Date": date} + + +def clean_bodywork(file_path): + data = [] + with open(file_path, "r") as file: + for line in file: + if line.strip(): + parsed_data = parse_body_line(line) + if parsed_data["Date"] is not None: + data.append(parsed_data) + df = pd.DataFrame(data) + df["Date"] = pd.to_datetime(df["Date"]) + fig = px.scatter( + df, + x="Date", + y="Plugin", + color="Plugin", + hover_data=["Description"], + title="Interactive Event Timeline from Volatility Body File (Detailed)", + labels={"Date": "Date", "Plugin": "Plugin Type"}, + template="plotly_white", + ) + fig.update_traces( + marker=dict(size=6, opacity=0.8) + ) # Adjust marker size and opacity + fig.update_layout( + xaxis_title="Date", + yaxis_title="Plugin Type", + legend_title="Plugin", + xaxis=dict( + rangeselector=dict( + buttons=list( + [ + dict(count=1, label="1m", step="month", stepmode="backward"), + dict(count=6, label="6m", step="month", stepmode="backward"), + dict(count=1, label="YTD", step="year", stepmode="todate"), + dict(count=1, label="1y", step="year", stepmode="backward"), + dict(step="all"), + ] + ) + ), + rangeslider=dict(visible=True), + type="date", + ), + yaxis=dict( + title="Plugin Type", + categoryorder="total ascending", # Order categories alphabetically or by event count + ), + hovermode="closest", # Improve hover interactions + height=600, # Adjust the height for better visibility + ) + return fig.to_html(full_html=False, default_height=500, default_width=700) diff --git a/orochi/website/views.py b/orochi/website/views.py index cfac3a4e..194dcc93 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -40,6 +40,7 @@ from volatility3.framework import automagic, contexts from orochi.utils.download_symbols import Downloader +from orochi.utils.timeliner import clean_bodywork from orochi.utils.volatility_dask_elk import ( check_runnable, get_banner, @@ -465,15 +466,15 @@ def analysis(request): or os.path.exists("/maxmind/GeoLite2-Country.mmdb") ) - bodyfile_path = ( - Path(res.dump.upload.path).parent - / "timeliner.Timeliner/volatility.body" - ) - bodyfile = ( - bodyfile_path - if plugin.name == "timeliner.Timeliner" and bodyfile_path.exists() - else None - ) + bodyfile = None + bodyfile_chart = None + if plugin.name == "timeliner.Timeliner": + bodyfile_path = ( + Path(res.dump.upload.path).parent + / "timeliner.Timeliner/volatility.body" + ) + bodyfile = bodyfile_path if bodyfile_path.exists() else None + bodyfile_chart = clean_bodywork(bodyfile_path) return render( request, @@ -484,6 +485,7 @@ def analysis(request): "plugin": plugin.name, "maxmind": maxmind, "bodyfile": bodyfile, + "bodyfile_chart": bodyfile_chart, }, ) diff --git a/requirements/base.txt b/requirements/base.txt index 9c500ec3..e43580b4 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -95,6 +95,10 @@ tornado==6.4.1 # https://pandas.pydata.org/ pandas==2.2.2 +# Plotting +# ------------------------------------------------------------------------------ +plotly==5.23.0 + # Volatility # ------------------------------------------------------------------------------ # https://github.com/volatilityfoundation/ From b8e506bc23d4d3b1d5bbe369bd5b5bc3ae0d4f54 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Tue, 6 Aug 2024 15:24:06 +0200 Subject: [PATCH 62/84] plot bodyfile chart --- orochi/website/views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/orochi/website/views.py b/orochi/website/views.py index 194dcc93..fda7c9b7 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -473,8 +473,9 @@ def analysis(request): Path(res.dump.upload.path).parent / "timeliner.Timeliner/volatility.body" ) - bodyfile = bodyfile_path if bodyfile_path.exists() else None - bodyfile_chart = clean_bodywork(bodyfile_path) + if bodyfile_path.exists(): + bodyfile = bodyfile_path + bodyfile_chart = clean_bodywork(bodyfile_path) return render( request, From f299ac2abda94841413f4f1b8bec6e27e90d7c49 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 7 Aug 2024 14:24:59 +0200 Subject: [PATCH 63/84] use go image to build dwarf2json --- compose/local/django/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index aa1f5d46..ce323516 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -34,10 +34,9 @@ RUN apt-get update \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && rm -rf /var/lib/apt/lists/* -FROM base-builder as go-builder +FROM golang:alpine3.20 as go-builder +RUN apk add git WORKDIR / -RUN curl https://dl.google.com/go/go1.22.0.linux-amd64.tar.gz --output go1.22.0.linux-amd64.tar.gz \ - && tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz RUN git clone https://github.com/volatilityfoundation/dwarf2json.git WORKDIR /dwarf2json RUN /usr/local/go/bin/go build From a4f89fb4624f19570f82e9bb1b77f9e204186585 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 7 Aug 2024 15:06:33 +0200 Subject: [PATCH 64/84] fix: command variables are now in defaults.py --- CHANGELOG.md | 5 +++++ orochi/website/management/commands/import_local.py | 9 ++------- orochi/website/management/commands/plugins_sync.py | 9 ++------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e6a9c26..2aa38715 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ * signal for dump/result changes are very verbose [[#1074](https://github.com/LDO-CERT/orochi/issues/1074)] * replace drf & co. with django-ninja [[#1073](https://github.com/LDO-CERT/orochi/issues/1073)] * Add experimental support for ARM64 + * Add Two-Factor Authentication [[#1099](https://github.com/LDO-CERT/orochi/issues/1099)] + * Admin: Assign multiple dumps to user [[#1082](https://github.com/LDO-CERT/orochi/issues/1082)] + * Multi-arch build and images [[#1098](https://github.com/LDO-CERT/orochi/issues/1098)] + * Custom logo in the login page [[#1083](https://github.com/LDO-CERT/orochi/issues/1083)] + * Manage BodyFile file in timeliner plugin
    diff --git a/orochi/website/management/commands/import_local.py b/orochi/website/management/commands/import_local.py index 85dbfdf4..581e3f92 100644 --- a/orochi/website/management/commands/import_local.py +++ b/orochi/website/management/commands/import_local.py @@ -6,13 +6,8 @@ from django.core.management.base import BaseCommand from django.db import transaction -from orochi.website.models import ( - RESULT_STATUS_NOT_STARTED, - RESULT_STATUS_RUNNING, - Dump, - Result, - UserPlugin, -) +from orochi.website.defaults import RESULT_STATUS_NOT_STARTED, RESULT_STATUS_RUNNING +from orochi.website.models import Dump, Result, UserPlugin from orochi.website.views import index_f_and_f diff --git a/orochi/website/management/commands/plugins_sync.py b/orochi/website/management/commands/plugins_sync.py index de683c10..34ae3297 100644 --- a/orochi/website/management/commands/plugins_sync.py +++ b/orochi/website/management/commands/plugins_sync.py @@ -4,13 +4,8 @@ from volatility3 import framework from volatility3.framework import contexts -from orochi.website.models import ( - RESULT_STATUS_NOT_STARTED, - Dump, - Plugin, - Result, - UserPlugin, -) +from orochi.website.defaults import RESULT_STATUS_NOT_STARTED +from orochi.website.models import Dump, Plugin, Result, UserPlugin class Command(BaseCommand): From 1f77aa4b4ef6905f931335e7bd35288bf202acba Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 28 Aug 2024 12:05:57 +0200 Subject: [PATCH 65/84] update js, python libs --- .pre-commit-config.yaml | 4 +- compose/local/{ => arm64}/arm.py | 545 +- compose/local/arm64/pdbscan.py | 458 + compose/local/arm64/windows.py | 565 + compose/local/dask/Dockerfile | 9 +- compose/local/django/Dockerfile | 9 +- compose/local/linux.py | 412 - config/settings/base.py | 2 +- orochi/static/README.txt | 16 +- orochi/static/css/bootstrap/bootstrap.min.css | 6 +- .../css/bootstrap/bootstrap.min.css.map | 121 +- .../css/datatables/dataTables.bootstrap5.css | 515 + .../datatables/dataTables.bootstrap5.min.css | 5 - .../css/datatables/jquery.dataTables.min.css | 2 +- .../css/datatables/select.dataTables.min.css | 2 +- orochi/static/css/fontawesome/all.min.css | 10 +- orochi/static/css/jsoneditor/jsoneditor.css | 2 +- .../static/css/webfonts/fa-brands-400.woff2 | Bin 108028 -> 118072 bytes .../static/css/webfonts/fa-regular-400.woff2 | Bin 24948 -> 25464 bytes orochi/static/css/webfonts/fa-solid-900.woff2 | Bin 150124 -> 157192 bytes orochi/static/css/wunderbaum/wunderbaum.css | 310 +- .../static/css/wunderbaum/wunderbaum.css.map | 2 +- .../js/bootstrap/bootstrap.bundle.min.js | 6 +- .../js/bootstrap/bootstrap.bundle.min.js.map | 2 +- .../js/datatables/dataTables.bootstrap5.js | 157 + .../datatables/dataTables.bootstrap5.min.js | 4 - .../datatables/dataTables.checkboxes.min.js | 4 +- .../dataTables.checkboxes.min.js.map | 2 +- orochi/static/js/datatables/dataTables.js | 13561 ++++++++++++++++ .../js/datatables/dataTables.select.min.js | 42 +- .../js/datatables/jquery.dataTables.min.js | 4 - orochi/static/js/fontawesome/all.min.js | 6 +- orochi/static/js/jscolor/jscolor.js | 8 +- orochi/static/js/jsoneditor/jsoneditor.map | 125 +- orochi/static/js/jsoneditor/jsoneditor.min.js | 84 +- orochi/static/js/marked/marked.min.js | 6 +- orochi/static/js/wunderbaum/wunderbaum.umd.js | 652 +- .../js/wunderbaum/wunderbaum.umd.min.js | 88 +- .../js/wunderbaum/wunderbaum.umd.min.js.map | 2 +- orochi/templates/base.html | 6 +- requirements/base.txt | 35 +- requirements/local.txt | 16 +- 42 files changed, 16407 insertions(+), 1398 deletions(-) rename compose/local/{ => arm64}/arm.py (57%) create mode 100644 compose/local/arm64/pdbscan.py create mode 100644 compose/local/arm64/windows.py delete mode 100644 compose/local/linux.py create mode 100644 orochi/static/css/datatables/dataTables.bootstrap5.css delete mode 100644 orochi/static/css/datatables/dataTables.bootstrap5.min.css create mode 100644 orochi/static/js/datatables/dataTables.bootstrap5.js delete mode 100644 orochi/static/js/datatables/dataTables.bootstrap5.min.js create mode 100644 orochi/static/js/datatables/dataTables.js delete mode 100644 orochi/static/js/datatables/jquery.dataTables.min.js diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9abf900b..8758d40d 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,14 +4,14 @@ fail_fast: true repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - repo: https://github.com/psf/black - rev: 24.4.2 + rev: 24.8.0 hooks: - id: black diff --git a/compose/local/arm.py b/compose/local/arm64/arm.py similarity index 57% rename from compose/local/arm.py rename to compose/local/arm64/arm.py index 45d4c1a9..28cb7916 100644 --- a/compose/local/arm.py +++ b/compose/local/arm64/arm.py @@ -2,14 +2,19 @@ # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # -import logging -import functools import collections -from typing import Optional, Dict, Any, List, Iterable, Tuple +import functools +import inspect +import json +import logging +import struct +from enum import Enum +from typing import Any, Dict, Iterable, List, Optional, Tuple from volatility3 import classproperty -from volatility3.framework import interfaces, exceptions +from volatility3.framework import exceptions, interfaces from volatility3.framework.configuration import requirements +from volatility3.framework.interfaces.configuration import path_join from volatility3.framework.layers import linear vollog = logging.getLogger(__name__) @@ -18,13 +23,23 @@ Webography : [1] Arm, "Arm Architecture Reference Manual for A-profile architecture, DDI 0487J.a (ID042523)", https://developer.arm.com/documentation/ddi0487/ja/?lang=en [2] Linux, Linux Kernel source code, v6.7 + [3] Arm, "Programmer's Guide for ARMv8-A", https://cs140e.sergio.bz/docs/ARMv8-A-Programmer-Guide.pdf Glossary : TTB : Translation Table Base TCR : Translation Control Register EL : Exception Level (0:Application,1:Kernel,2:Hypervisor,3:Secure Monitor) Granule : Translation granule (smallest block of memory that can be described) - """ + +Definitions : + + The OS-controlled translation is called stage 1 translation, and the hypervisor-controlled translation is called stage 2 translation. + +Notes : + If hardware management of the dirty state is enabled, the DBM bit is set to 1. ([1], D8.4.6) + If hardware management of the Access Flag bit is not enabled, software must implement it. ([1], D8.4.5) + Access Permissions bits can be updated by hardware in some situations, but is mostly managed by software. ([1], D8.4.3) +""" class AArch64Exception(exceptions.LayerException): @@ -68,22 +83,44 @@ def __init__( super().__init__( context=context, config_path=config_path, name=name, metadata=metadata ) - self._kernel_endianness = self.config["kernel_endianness"] + + # Unserialize cpu_registers config attribute into a dict + self._cpu_regs = self.config["cpu_registers"] + try: + self._cpu_regs: dict = json.loads(self._cpu_regs) + except json.JSONDecodeError as e: + raise json.JSONDecodeError( + 'Could not JSON deserialize provided "cpu_registers" layer requirement.', + e.doc, + e.pos, + ) + self._cpu_regs_mapped = self._map_reg_values(self._cpu_regs) + + self._entry_format = self.config["entry_format"] self._layer_debug = self.config.get("layer_debug", False) self._translation_debug = self.config.get("translation_debug", False) self._base_layer = self.config["memory_layer"] # self._swap_layers = [] # TODO self._page_map_offset = self.config["page_map_offset"] - self._page_map_offset_kernel = self.config["page_map_offset_kernel"] - self._ttbs_tnsz = [self.config["tcr_el1_t0sz"], self.config["tcr_el1_t1sz"]] + self._page_map_offset_kernel = self._read_register_field( + AArch64RegMap.TTBR1_EL1.BADDR + ) + self._ttbs_tnsz = [ + self._read_register_field(AArch64RegMap.TCR_EL1.T0SZ), + self._read_register_field(AArch64RegMap.TCR_EL1.T1SZ), + ] self._ttbs_granules = [ - self.config["page_size_user_space"], - self.config["page_size_kernel_space"], + AArch64RegFieldValues._get_ttbr0_el1_granule_size( + self._read_register_field(AArch64RegMap.TCR_EL1.TG0) + ), + AArch64RegFieldValues._get_ttbr1_el1_granule_size( + self._read_register_field(AArch64RegMap.TCR_EL1.TG1) + ), ] # Context : TTB0 (user) or TTB1 (kernel) self._virtual_addr_space = int( - self._page_map_offset == self.config["page_map_offset_kernel"] + self._page_map_offset == self._page_map_offset_kernel ) # [1], see D8.1.9, page 5818 @@ -94,47 +131,41 @@ def __init__( smallest block of memory that can be described. Possibles values are 4, 16 or 64 (kB). """ - self._is_52bits = ( - True if self._ttbs_tnsz[self._virtual_addr_space] < 16 else False - ) + self._is_52bits = True if self._ttb_bitsize < 16 else False self._ttb_lookup_indexes = self._determine_ttb_lookup_indexes( self._ttb_granule, self._ttb_bitsize ) self._ttb_descriptor_bits = self._determine_ttb_descriptor_bits( self._ttb_granule, self._ttb_lookup_indexes, self._is_52bits ) - self._virtual_addr_range = self._get_virtual_addr_range()[ - self._virtual_addr_space - ] + self._virtual_addr_range = self._get_virtual_addr_range() self._canonical_prefix = self._mask( (1 << self._bits_per_register) - 1, self._bits_per_register, self._ttb_bitsize, ) - if self._layer_debug: - self._print_layer_debug_informations() - @property - @functools.lru_cache() - def page_shift(self) -> int: - """Page shift for this layer, which is the page size bit length. - - Typical values : 12, 14, 16 - """ - return self.page_size.bit_length() - 1 + # [1], see D8.3, page 5852 + if self._is_52bits: + if self._ttb_granule in [4, 16]: + self._ta_51_x_bits = (9, 8) + elif self._ttb_granule == 64: + self._ta_51_x_bits = (15, 12) - @property - @functools.lru_cache() - def page_size(self) -> int: - """Page size of this layer, in bytes. - - Typical values : 4096, 16384, 65536 - """ - return self._ttb_granule * 1024 + self._page_size = self._ttb_granule * 1024 + self._page_size_in_bits = self._page_size.bit_length() - 1 + self._entry_size = struct.calcsize(self._entry_format) + self._entry_number = self._page_size // self._entry_size - @property - @functools.lru_cache() - def page_mask(cls) -> int: - """Page mask for this layer.""" - return ~(cls.page_size - 1) + # CPU features + hafdbs = self._read_register_field(AArch64RegMap.ID_AA64MMFR1_EL1.HAFDBS, True) + if hafdbs: + self._feat_hafdbs = AArch64RegFieldValues._get_feature_HAFDBS(hafdbs) + else: + self._feat_hafdbs = None + + if self._layer_debug: + self._print_layer_debug_informations() def _print_layer_debug_informations(self) -> None: vollog.debug(f"Base layer : {self._base_layer}") @@ -145,9 +176,7 @@ def _print_layer_debug_informations(self) -> None: f"Virtual addresses space range : {tuple([hex(x) for x in self._get_virtual_addr_range()])}" ) vollog.debug(f"Page size : {self._ttb_granule}") - vollog.debug( - f"T{self._virtual_addr_space}SZ : {self._ttbs_tnsz[self._virtual_addr_space]}" - ) + vollog.debug(f"T{self._virtual_addr_space}SZ : {self._ttb_bitsize}") vollog.debug(f"Page map offset : {hex(self._page_map_offset)}") vollog.debug(f"Translation mappings : {self._ttb_lookup_indexes}") @@ -210,40 +239,33 @@ def _translate_entry(self, virtual_offset: int) -> Tuple[int, int, int]: """ base_layer = self.context.layers[self._base_layer] - # [1], see D8.2.4, page 5824 + # [1], see D8.2.4, page 5825 ttb_selector = self._mask(virtual_offset, 55, 55) - # Check if requested address belongs to the context virtual memory space + # Check if requested address belongs to the virtual memory space context if ttb_selector != self._virtual_addr_space: raise exceptions.InvalidAddressException( layer_name=self.name, invalid_address=virtual_offset, ) - # [1], see D8.3, page 5852 - if self._is_52bits: - if self._ttb_granule in [4, 16]: - ta_51_x_bits = (9, 8) - elif self._ttb_granule == 64: - ta_51_x_bits = (15, 12) - table_address = self._page_map_offset max_level = len(self._ttb_lookup_indexes) - 1 for level, (high_bit, low_bit) in enumerate(self._ttb_lookup_indexes): index = self._mask(virtual_offset, high_bit, low_bit) - descriptor = int.from_bytes( + (descriptor,) = struct.unpack( + self._entry_format, base_layer.read( table_address + (index * self._register_size), self._register_size ), - byteorder=self._kernel_endianness, ) table_address = 0 # Bits 51->x need to be extracted from the descriptor if self._is_52bits: ta_51_x = self._mask( descriptor, - ta_51_x_bits[0], - ta_51_x_bits[1], + self._ta_51_x_bits[0], + self._ta_51_x_bits[1], ) table_address = ta_51_x << (52 - ta_51_x.bit_length()) @@ -259,6 +281,13 @@ def _translate_entry(self, virtual_offset: int) -> Tuple[int, int, int]: ) << self._ttb_descriptor_bits[1] ) + if self._get_valid_table(table_address) == None: + raise exceptions.PagedInvalidAddressException( + layer_name=self.name, + invalid_address=virtual_offset, + invalid_bits=low_bit, + entry=descriptor, + ) # Block descriptor elif level < max_level and descriptor_type == 0b01: table_address |= ( @@ -297,6 +326,18 @@ def _translate_entry(self, virtual_offset: int) -> Tuple[int, int, int]: return table_address, low_bit, descriptor + @functools.lru_cache(1025) + def _get_valid_table(self, base_address: int) -> Optional[bytes]: + """Extracts the translation table, validates it and returns it if it's valid.""" + table = self._context.layers.read( + self._base_layer, base_address, self.page_size + ) + # If the table is entirely duplicates, then mark the whole table as bad + if table == table[: self._entry_size] * self._entry_number: + return None + + return table + def mapping( self, offset: int, length: int, ignore_errors: bool = False ) -> Iterable[Tuple[int, int, int, int, str]]: @@ -345,26 +386,8 @@ def _mapping( self, offset: int, length: int, ignore_errors: bool = False ) -> Iterable[Tuple[int, int, int, int, str]]: """Returns a sorted iterable of (offset, sublength, mapped_offset, mapped_length, layer) - mappings. + mappings.This allows translation layers to provide maps of contiguous regions in one layer. - This allows translation layers to provide maps of contiguous - regions in one layer - """ - if length == 0: - try: - mapped_offset, _, layer_name = self._translate(offset) - if not self._context.layers[layer_name].is_valid(mapped_offset): - raise exceptions.InvalidAddressException( - layer_name=layer_name, invalid_address=mapped_offset - ) - except exceptions.InvalidAddressException: - if not ignore_errors: - raise - return None - yield offset, length, mapped_offset, length, layer_name - return None - while length > 0: - """ A bit of lexical definition : "page" means "virtual page" (i.e. a chunk of virtual address space) and "page frame" means "physical page" (i.e. a chunk of physical memory). What this is actually doing : @@ -382,7 +405,22 @@ def _mapping( -> 4096 - 0x0 = 4096 -> 0xffff800000f93000 + 4096 = 0xffff800000f94000 etc. while "length" > 0 - """ + """ + + if length == 0: + try: + mapped_offset, _, layer_name = self._translate(offset) + if not self._context.layers[layer_name].is_valid(mapped_offset): + raise exceptions.InvalidAddressException( + layer_name=layer_name, invalid_address=mapped_offset + ) + except exceptions.InvalidAddressException: + if not ignore_errors: + raise + return None + yield offset, length, mapped_offset, length, layer_name + return None + while length > 0: try: chunk_offset, page_size, layer_name = self._translate(offset) chunk_size = min(page_size - (chunk_offset % page_size), length) @@ -401,11 +439,11 @@ def _mapping( """ if not ignore_errors: raise - # We can jump more if we know where the page fault failed + # We can jump more if we know where the page fault occured if isinstance(excp, exceptions.PagedInvalidAddressException): mask = (1 << excp.invalid_bits) - 1 else: - mask = (1 << (self._ttb_granule.bit_length() - 1)) - 1 + mask = (1 << self.page_shift) - 1 length_diff = mask + 1 - (offset & mask) length -= length_diff offset += length_diff @@ -449,28 +487,109 @@ def is_dirty(self, offset: int) -> bool: """Returns whether the page at offset is marked dirty""" return self._page_is_dirty(self._translate_entry(offset)[2]) - @staticmethod - def _page_is_dirty(entry: int) -> bool: - """Returns whether a particular page is dirty based on its entry. - The bit indicates that its associated block of memory - has been modified and has not been saved to storage yet + def _page_is_dirty(self, entry: int) -> bool: + """ + Hardware management of the dirty state (only >= Armv8.1-A). - Hardware management (only > Armv8.1-A) : https://developer.arm.com/documentation/102376/0200/Access-Flag/Dirty-state - + [1], see D8.4.6, page 5877 and [1], see D8-16, page 5857 + General documentation : + https://developer.arm.com/documentation/102376/0200/Access-Flag/Dirty-state + + Technical documentation : + [1], see D8.4.6, page 5877 : "Hardware management of the dirty state" + [1], see D8-16 and page 5861 : "Stage 1 attribute fields in Block and Page descriptors" + + > For the purpose of FEAT_HAFDBS, a Block descriptor or Page descriptor can be described as having one of the following states: + • Non-writeable. + • Writeable-clean. + • Writeable-dirty. + + [1], see D8-41, page 5868 : + AP[2] | Access permission + -------|------------------ + 0 | Read/write + 1 | Read-only """ - # The following is based on Linux software implementation : - # [2], see arch/arm64/include/asm/pgtable-prot.h#L18 - return bool(entry & (1 << 55)) + if self._feat_hafdbs: + # Dirty Bit Modifier and Access Permissions bits + # DBM == 1 and AP == 0 -> HW dirty state + return bool((entry & (1 << 51)) and not (entry & (1 << 7))) + else: + raise NotImplementedError( + "Hardware updates to Access flag and Dirty state in translation tables are not available in the target kernel. Please try using a software based implementation of dirty bit management." + ) - @classproperty + @property @functools.lru_cache() - def minimum_address(cls) -> int: - return 0 + def page_shift(self) -> int: + """Page shift for this layer, which is the page size bit length. + - Typical values : 12, 14, 16 + """ + return self._page_size_in_bits + + @property + @functools.lru_cache() + def page_size(self) -> int: + """Page size for this layer, in bytes. + - Typical values : 4096, 16384, 65536 + """ + return self._page_size + + @property + @functools.lru_cache() + def page_mask(self) -> int: + """Page mask for this layer.""" + return self.page_size - 1 @classproperty @functools.lru_cache() - def maximum_address(cls) -> int: - return (1 << cls._maxvirtaddr) - 1 + def bits_per_register(cls) -> int: + """Returns the bits_per_register to determine the range of an + AArch64TranslationLayer.""" + return cls._bits_per_register + + @property + @functools.lru_cache() + def minimum_address(self) -> int: + return self._virtual_addr_range[0] + + @property + @functools.lru_cache() + def maximum_address(self) -> int: + return self._virtual_addr_range[1] + + def _read_register_field( + self, register_field: Enum, ignore_errors: bool = False + ) -> int: + reg_field_path = str(register_field) + try: + return self._cpu_regs_mapped[reg_field_path] + except KeyError: + if ignore_errors: + return None + raise KeyError( + f"{reg_field_path} register field wasn't provided to this layer initially." + ) + + @classmethod + def _map_reg_values(cls, registers_values: dict) -> dict: + """Generates a dict of dot joined AArch64 CPU registers and fields. + Iterates over every mapped register in AArch64RegMap, + check if a register value was provided to this layer, + mask every field accordingly and store the result. + + Example return value : {'ID_AA64MMFR1_EL1.HAFDBS': 2} + """ + + masked_trees = {} + for mm_cls_name, mm_cls in inspect.getmembers(AArch64RegMap, inspect.isclass): + if issubclass(mm_cls, Enum) and mm_cls_name in registers_values.keys(): + reg_value = registers_values[mm_cls_name] + for field in mm_cls: + dot_joined = path_join(mm_cls_name, field.name) + high_bit, low_bit = field.value + masked_value = cls._mask(reg_value, high_bit, low_bit) + masked_trees[dot_joined] = masked_value + return masked_trees def canonicalize(self, addr: int) -> int: """Canonicalizes an address by performing an appropiate sign extension on the higher addresses""" @@ -518,36 +637,16 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface] optional=False, description='DTB of the target context (either "kernel space" or "user space process").', ), - requirements.IntRequirement( - name="page_map_offset_kernel", - optional=False, - description="DTB of the kernel space, it is primarily used to determine the target context of the layer (page_map_offset == page_map_offset_kernel). Conveniently calculated by LinuxStacker.", - ), - requirements.IntRequirement( - name="tcr_el1_t0sz", - optional=False, - description="The size offset of the memory region addressed by TTBR0_EL1. Conveniently calculated by LinuxStacker.", - ), - requirements.IntRequirement( - name="tcr_el1_t1sz", - optional=False, - description="The size offset of the memory region addressed by TTBR1_EL1. Conveniently calculated by LinuxStacker.", - ), - requirements.IntRequirement( - name="page_size_user_space", - optional=False, - description="Page size used by the user address space. Conveniently calculated by LinuxStacker.", - ), - requirements.IntRequirement( - name="page_size_kernel_space", + requirements.StringRequirement( + name="entry_format", optional=False, - description="Page size used by the kernel address space. Conveniently calculated by LinuxStacker.", + description='Format and byte order of table descriptors, represented in the "struct" format.', ), - requirements.ChoiceRequirement( - choices=["little", "big"], - name="kernel_endianness", + requirements.StringRequirement( + name="cpu_registers", optional=False, - description="Kernel endianness (little or big)", + description="Serialized dict of cpu register keys bound to their corresponding value. Needed for specific (non-mandatory) uses (ex: dirty bit management).", + default="{}", ), requirements.BooleanRequirement( name="layer_debug", @@ -570,3 +669,213 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface] description="Kernel unique identifier, including compiler name and version, kernel version, compile time.", ), ] + + +class LinuxAArch64Mixin(AArch64): + def _page_is_dirty(self, entry: int) -> bool: + """Returns whether a particular page is dirty based on its (page table) entry. + The bit indicates that its associated block of memory + has been modified and has not been saved to storage yet. + + The following is based on Linux software AArch64 dirty bit management. + [2], see arch/arm64/include/asm/pgtable-prot.h#L18 + [3], see page 12-25 + https://lkml.org/lkml/2023/7/7/77 -> Linux implementation detail + """ + sw_dirty = bool(entry & (1 << 55)) + try: + hw_dirty = super()._page_is_dirty(entry) + return sw_dirty or hw_dirty + except NotImplementedError: + return sw_dirty + + +class LinuxAArch64(LinuxAArch64Mixin, AArch64): + pass + + +class WindowsAArch64Mixin(AArch64): + def _page_is_dirty(self, entry: int) -> bool: + """Returns whether a particular page is dirty based on its (page table) entry. + The bit indicates that its associated block of memory + has been modified and has not been saved to storage yet. + + The following is based on the Windows kernel function MiMarkPteDirty(). + Windows software DBM bit is located at offset 56, and does not account + of hardware bit 51. + """ + return bool((entry & (1 << 56)) and not (entry & (1 << 7))) + + +class WindowsAArch64(WindowsAArch64Mixin, AArch64): + """Windows AArch64 page size is constant, and statically defined in + CmSiGetPageSize() kernel function. + + Takes advantage of the @classproperty, as @property is dynamic + and breaks static accesses in windows automagic. + """ + + @classproperty + @functools.lru_cache() + def page_shift(self) -> int: + """Page shift for this layer, which is the page size bit length.""" + return 12 + + @classproperty + @functools.lru_cache() + def page_size(self) -> int: + """Page size for this layer, in bytes. + Prefer returning the value directly, instead of adding an additional + "_page_size" constant that could cause confusion with the parent class. + """ + return 0x1000 + + @classproperty + @functools.lru_cache() + def page_mask(self) -> int: + """Page mask for this layer.""" + return self.page_size - 1 + + +"""Avoid cluttering the layer code with static mappings.""" + + +class AArch64RegMap: + """ + List of static Enum's, binding fields (high bit, low bit) of AArch64 CPU registers. + Prevents the use of hardcoded string values by unifying everything here. + Contains only essential mappings, needed by the framework. + """ + + class TCR_EL1(Enum): + """TCR_EL1, Translation Control Register (EL1). + The control register for stage 1 of the EL1&0 translation regime. + [1], see D19.2.139, page 7071 + """ + + TG1 = (31, 30) + "Granule size for the TTBR1_EL1." + T1SZ = (21, 16) + "The size offset of the memory region addressed by TTBR1_EL1. The region size is 2**(64-T1SZ) bytes." + TG0 = (15, 14) + "Granule size for the TTBR0_EL1." + T0SZ = (5, 0) + "The size offset of the memory region addressed by TTBR0_EL1. The region size is 2**(64-T0SZ) bytes." + + class TTBR0_EL1(Enum): + """TTBR0_EL1, Translation Table Base Register 0 (EL1) + Holds the base address of the translation table for the initial lookup for stage 1 of the translation of an address from the lower VA range in the EL1&0 translation regime, and other information for this translation regime. [1], see D19.2.155, page 7152 + [1], see D19.2.152, page 7139 + """ + + ASID = (63, 48) + BADDR = (47, 1) + CnP = (0, 0) + + class TTBR1_EL1(Enum): + """TTBR1_EL1, Translation Table Base Register 1 (EL1) + Holds the base address of the translation table for the initial lookup for stage 1 of the translation of an address from the higher VA range in the EL1&0 stage 1 translation regime, and other information for this translation regime. + [1], see D19.2.155, page 7152 + """ + + ASID = (63, 48) + BADDR = (47, 1) + CnP = (0, 0) + + class ID_AA64MMFR1_EL1(Enum): + """ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1. + [1], see D19.2.65, page 6781""" + + HAFDBS = (3, 0) + "Hardware updates to Access flag and Dirty state in translation tables." + + +class AArch64RegFieldValues: + @classmethod + def _table_lookup( + cls, value: int, lookup_table: dict, reverse_lookup: bool = False + ): + if reverse_lookup: + lookup_table = {v: k for k, v in lookup_table.items()} + if lookup_table.get(value, None) != None: + return lookup_table[value] + else: + raise KeyError( + f"Value {value} could not be mapped inside lookup_table : {lookup_table}" + ) + + @classmethod + def _get_feature_HAFDBS(cls, value: int) -> bool: + """ + Hardware updates to Access flag and Dirty state in translation tables. + [1], see D19.2.65, page 6784 + """ + return value >= 0b10 + + @classmethod + def _get_ttbr0_el1_granule_size(cls, value: int, reverse_lookup: bool = False): + """ + Granule size for the TTBR0_EL1. + """ + lookup_table = { + 0b00: 4, # 4kB + 0b01: 64, # 64kB + 0b10: 16, # 16kB + } + return cls._table_lookup(value, lookup_table, reverse_lookup) + + @classmethod + def _get_ttbr1_el1_granule_size( + cls, value: int, reverse_lookup: bool = False + ) -> Optional[int]: + """ + Granule size for the TTBR1_EL1. + """ + lookup_table = { + 0b01: 16, # 16kB + 0b10: 4, # 4kB + 0b11: 64, # 64kB + } + return cls._table_lookup(value, lookup_table, reverse_lookup) + + +def set_reg_bits(value: int, reg_field: Enum, reg_value: int = 0) -> int: + """Sets the bits from high_bit to low_bit (inclusive) in current_value to the given value. + Allows to manipulate the bits at arbitrary positions inside a register. + + Args: + value: The value to set in the specified bit range. + reg_field: The register field to update, inside the register. + reg_value: The register value to modify (default is 0). + + Returns: + The modified integer with the specified bits set. + + Raises: + ValueError: If the value is too large to fit in the specified bit range. + """ + high_bit = reg_field.value[1] + low_bit = reg_field.value[0] + + # Calculate the number of bits to set + num_bits = low_bit - high_bit + 1 + + # Calculate the maximum value that can fit in the specified number of bits + max_value = (1 << num_bits) - 1 + + # Check if the value can fit in the specified bit range + if value > max_value: + raise ValueError( + f"Value {value} is too large to fit in {num_bits} bits (max value is {max_value})." + ) + + # Create a mask for the bit range + mask = (1 << num_bits) - 1 + + # Clear the bits in the range in the current value + reg_value &= ~(mask << high_bit) + + # Set the bits with the new value + reg_value |= (value & mask) << high_bit + + return reg_value diff --git a/compose/local/arm64/pdbscan.py b/compose/local/arm64/pdbscan.py new file mode 100644 index 00000000..7a6a9306 --- /dev/null +++ b/compose/local/arm64/pdbscan.py @@ -0,0 +1,458 @@ +# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 +# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 +# +"""A module for scanning translation layers looking for Windows PDB records +from loaded PE files. + +This module contains a standalone scanner, and also a :class:`~volatility3.framework.interfaces.layers.ScannerInterface` +based scanner for use within the framework by calling :func:`~volatility3.framework.interfaces.layers.DataLayerInterface.scan`. +""" +import contextlib +import logging +import math +import os +from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Union + +from volatility3.framework import constants, exceptions, interfaces, layers +from volatility3.framework.configuration import requirements +from volatility3.framework.layers import intel, scanners +from volatility3.framework.symbols import native +from volatility3.framework.symbols.windows.pdbutil import PDBUtility + +if __name__ == "__main__": + import sys + + sys.path.append( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) + ) + +vollog = logging.getLogger(__name__) + +ValidKernelType = Tuple[str, int, Dict[str, Optional[Union[bytes, str, int]]]] +KernelsType = Iterable[Dict[str, Any]] + + +class KernelPDBScanner(interfaces.automagic.AutomagicInterface): + """Windows symbol loader based on PDB signatures. + + An Automagic object that looks for all Intel translation layers and scans each of them for a pdb signature. + When found, a search for a corresponding Intermediate Format data file is carried out and if found an appropriate + symbol space is automatically loaded. + + Once a specific kernel PDB signature has been found, a virtual address for the loaded kernel is determined + by one of two methods. The first method assumes a specific mapping from the kernel's physical address to its + virtual address (typically the kernel is loaded at its physical location plus a specific offset). The second method + searches for a particular structure that lists the kernel module's virtual address, its size (not checked) and the + module's name. This value is then used if one was not found using the previous method. + """ + + priority = 30 + max_pdb_size = 0x400000 + exclusion_list = ["linux", "mac"] + + def find_virtual_layers_from_req( + self, + context: interfaces.context.ContextInterface, + config_path: str, + requirement: interfaces.configuration.RequirementInterface, + ) -> List[str]: + """Traverses the requirement tree, rooted at `requirement` looking for + virtual layers that might contain a windows PDB. + + Returns a list of possible layers + + Args: + context: The context in which the `requirement` lives + config_path: The path within the `context` for the `requirement`'s configuration variables + requirement: The root of the requirement tree to search for :class:~`volatility3.framework.interfaces.layers.TranslationLayerRequirement` objects to scan + + Returns: + A list of (layer_name, scan_results) + """ + sub_config_path = interfaces.configuration.path_join( + config_path, requirement.name + ) + results: List[str] = [] + if isinstance(requirement, requirements.TranslationLayerRequirement): + # Check for symbols in this layer + # FIXME: optionally allow a full (slow) scan + # FIXME: Determine the physical layer no matter the virtual layer + virtual_layer_name = context.config.get(sub_config_path, None) + layer_name = context.config.get( + interfaces.configuration.path_join(sub_config_path, "memory_layer"), + None, + ) + if layer_name and virtual_layer_name: + memlayer = context.layers[virtual_layer_name] + if isinstance(memlayer, intel.Intel) or isinstance( + memlayer, layers.arm.AArch64 + ): + results = [virtual_layer_name] + else: + for subreq in requirement.requirements.values(): + results += self.find_virtual_layers_from_req( + context, sub_config_path, subreq + ) + return results + + def recurse_symbol_fulfiller( + self, + context: interfaces.context.ContextInterface, + valid_kernel: ValidKernelType, + progress_callback: constants.ProgressCallback = None, + ) -> None: + """Fulfills the SymbolTableRequirements in `self._symbol_requirements` + found by the `recurse_symbol_requirements`. + + This pass will construct any requirements that may need it in the context it was passed + + Args: + context: Context on which to operate + valid_kernel: A list of offsets where valid kernels have been found + progress_callback: Means of providing the user with feedback during long processes + """ + for sub_config_path, requirement in self._symbol_requirements: + # TODO: Potentially think about multiple symbol requirements in both the same and different levels of the requirement tree + # TODO: Consider whether a single found kernel can fulfill multiple requirements + if valid_kernel: + # TODO: Check that the symbols for this kernel will fulfill the requirement + virtual_layer, _kvo, kernel = valid_kernel + if not isinstance(kernel["pdb_name"], str) or not isinstance( + kernel["GUID"], str + ): + raise TypeError("PDB name or GUID not a string value") + + PDBUtility.load_windows_symbol_table( + context=context, + guid=kernel["GUID"], + age=kernel["age"], + pdb_name=kernel["pdb_name"], + symbol_table_class="volatility3.framework.symbols.windows.WindowsKernelIntermedSymbols", + config_path=sub_config_path, + progress_callback=progress_callback, + ) + else: + vollog.debug("No suitable kernel pdb signature found") + + def set_kernel_virtual_offset( + self, + context: interfaces.context.ContextInterface, + valid_kernel: ValidKernelType, + ) -> None: + """Traverses the requirement tree, looking for kernel_virtual_offset + values that may need setting and sets it based on the previously + identified `valid_kernel`. + + Args: + context: Context on which to operate and provide the kernel virtual offset + valid_kernel: List of valid kernels and offsets + """ + if valid_kernel: + # Set the virtual offset under the TranslationLayer it applies to + virtual_layer, kvo, kernel = valid_kernel + if kvo is not None: + kvo_path = interfaces.configuration.path_join( + context.layers[virtual_layer].config_path, "kernel_virtual_offset" + ) + context.config[kvo_path] = kvo + vollog.debug(f"Setting kernel_virtual_offset to {hex(kvo)}") + + def get_physical_layer_name(self, context, vlayer): + return context.config.get( + interfaces.configuration.path_join(vlayer.config_path, "memory_layer"), None + ) + + def method_slow_scan( + self, + context: interfaces.context.ContextInterface, + vlayer: layers.intel.Intel, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + def test_virtual_kernel( + physical_layer_name, virtual_layer_name: str, kernel: Dict[str, Any] + ) -> Optional[ValidKernelType]: + # It seems the kernel is loaded at a fixed mapping (presumably because the memory manager hasn't started yet) + if kernel["mz_offset"] is None or not isinstance(kernel["mz_offset"], int): + # Rule out kernels that couldn't find a suitable MZ header + return None + return (virtual_layer_name, kernel["mz_offset"], kernel) + + vollog.debug("Kernel base determination - optimized scan virtual layer") + valid_kernel = self._method_layer_pdb_scan( + context, vlayer, test_virtual_kernel, True, False, progress_callback + ) + if valid_kernel is not None: + return valid_kernel + + vollog.debug("Kernel base determination - slow scan virtual layer") + return self._method_layer_pdb_scan( + context, vlayer, test_virtual_kernel, False, False, progress_callback + ) + + def method_fixed_mapping( + self, + context: interfaces.context.ContextInterface, + vlayer: layers.intel.Intel, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + def test_physical_kernel( + physical_layer_name: str, virtual_layer_name: str, kernel: Dict[str, Any] + ) -> Optional[ValidKernelType]: + # It seems the kernel is loaded at a fixed mapping (presumably because the memory manager hasn't started yet) + if kernel["mz_offset"] is None or not isinstance(kernel["mz_offset"], int): + # Rule out kernels that couldn't find a suitable MZ header + return None + if vlayer.bits_per_register == 64: + kvo = kernel["mz_offset"] + ( + 31 << int(math.ceil(math.log2(vlayer.maximum_address + 1)) - 5) + ) + else: + kvo = kernel["mz_offset"] + (1 << (vlayer.bits_per_register - 1)) + try: + kvp = vlayer.mapping(kvo, 0) + if any( + [ + (p == kernel["mz_offset"] and layer_name == physical_layer_name) + for (_, _, p, _, layer_name) in kvp + ] + ): + return (virtual_layer_name, kvo, kernel) + else: + vollog.debug( + "Potential kernel_virtual_offset did not map to expected location: {}".format( + hex(kvo) + ) + ) + except exceptions.InvalidAddressException: + vollog.debug( + f"Potential kernel_virtual_offset caused a page fault: {hex(kvo)}" + ) + return None + + vollog.debug("Kernel base determination - testing fixed base address") + return self._method_layer_pdb_scan( + context, vlayer, test_physical_kernel, False, True, progress_callback + ) + + def _method_layer_pdb_scan( + self, + context: interfaces.context.ContextInterface, + vlayer: layers.intel.Intel, + test_kernel: Callable, + optimized: bool = False, + physical: bool = True, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + # TODO: Verify this is a windows image + valid_kernel = None + virtual_layer_name = vlayer.name + physical_layer_name = self.get_physical_layer_name(context, vlayer) + + layer_to_scan = physical_layer_name + if not physical: + layer_to_scan = virtual_layer_name + + start_scan_address = 0 + if ( + optimized + and not physical + and context.layers[layer_to_scan].metadata.architecture + in ["Intel64", "AArch64"] + ): + # TODO: change this value accordingly when 5-Level paging is supported. + start_scan_address = 0x1F0 << 39 + + kernel_pdb_names = [ + bytes(name + ".pdb", "utf-8") + for name in constants.windows.KERNEL_MODULE_NAMES + ] + kernels = PDBUtility.pdbname_scan( + ctx=context, + layer_name=layer_to_scan, + start=start_scan_address, + page_size=vlayer.page_size, + pdb_names=kernel_pdb_names, + progress_callback=progress_callback, + ) + for kernel in kernels: + valid_kernel = test_kernel(physical_layer_name, virtual_layer_name, kernel) + if valid_kernel is not None: + break + return valid_kernel + + def _method_offset( + self, + context: interfaces.context.ContextInterface, + vlayer: layers.intel.Intel, + pattern: bytes, + result_offset: int, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + """Method for finding a suitable kernel offset based on a module + table.""" + vollog.debug( + "Kernel base determination - searching layer module list structure" + ) + valid_kernel: Optional[ValidKernelType] = None + # If we're here, chances are high we're in a Win10 x64 image with kernel base randomization + physical_layer_name = self.get_physical_layer_name(context, vlayer) + physical_layer = context.layers[physical_layer_name] + # TODO: On older windows, this might be \WINDOWS\system32\nt rather than \SystemRoot\system32\nt + results = physical_layer.scan( + context, scanners.BytesScanner(pattern), progress_callback=progress_callback + ) + seen: Set[int] = set() + # Because this will launch a scan of the virtual layer, we want to be careful + for result in results: + # TODO: Identify the specific structure we're finding and document this a bit better + pointer = context.object( + "pdbscan!unsigned long long", + offset=(result + result_offset), + layer_name=physical_layer_name, + ) + address = pointer & vlayer.address_mask + if address in seen: + continue + seen.add(address) + + valid_kernel = self.check_kernel_offset( + context, vlayer, address, progress_callback + ) + + if valid_kernel: + break + return valid_kernel + + def method_module_offset( + self, + context: interfaces.context.ContextInterface, + vlayer: layers.intel.Intel, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + return self._method_offset( + context, + vlayer, + b"\\SystemRoot\\system32\\nt", + -16 - int(vlayer.bits_per_register / 8), + progress_callback, + ) + + def method_kdbg_offset( + self, + context: interfaces.context.ContextInterface, + vlayer: layers.intel.Intel, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + return self._method_offset(context, vlayer, b"KDBG", 8, progress_callback) + + def check_kernel_offset( + self, + context: interfaces.context.ContextInterface, + vlayer: layers.intel.Intel, + address: int, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + """Scans a virtual address.""" + # Scan a few megs of the virtual space at the location to see if they're potential kernels + + valid_kernel: Optional[ValidKernelType] = None + kernel_pdb_names = [ + bytes(name + ".pdb", "utf-8") + for name in constants.windows.KERNEL_MODULE_NAMES + ] + + virtual_layer_name = vlayer.name + with contextlib.suppress(exceptions.InvalidAddressException): + if vlayer.read(address, 0x2) == b"MZ": + res = list( + PDBUtility.pdbname_scan( + ctx=context, + layer_name=vlayer.name, + page_size=vlayer.page_size, + pdb_names=kernel_pdb_names, + progress_callback=progress_callback, + start=address, + end=address + self.max_pdb_size, + ) + ) + if res: + valid_kernel = (virtual_layer_name, address, res[0]) + return valid_kernel + + # List of methods to be run, in order, to determine the valid kernels + methods = [ + method_kdbg_offset, + method_module_offset, + method_fixed_mapping, + method_slow_scan, + ] + + def determine_valid_kernel( + self, + context: interfaces.context.ContextInterface, + potential_layers: List[str], + progress_callback: constants.ProgressCallback = None, + ) -> Optional[ValidKernelType]: + """Runs through the identified potential kernels and verifies their + suitability. + + This carries out a scan using the pdb_signature scanner on a physical layer. It uses the + results of the scan to determine the virtual offset of the kernel. On early windows implementations + there is a fixed mapping between the physical and virtual addresses of the kernel. On more recent versions + a search is conducted for a structure that will identify the kernel's virtual offset. + + Args: + context: Context on which to operate + potential_layers: List of layer names that the kernel might live at + progress_callback: Function taking a percentage and optional description to be called during expensive computations to indicate progress + + Returns: + A dictionary of valid kernels + """ + valid_kernel: Optional[ValidKernelType] = None + for virtual_layer_name in potential_layers: + vlayer = context.layers.get(virtual_layer_name, None) + if isinstance(vlayer, layers.intel.Intel) or isinstance( + vlayer, layers.arm.AArch64 + ): + for method in self.methods: + valid_kernel = method(self, context, vlayer, progress_callback) + if valid_kernel: + break + if not valid_kernel: + vollog.info("No suitable kernels found during pdbscan") + return valid_kernel + + def __call__( + self, + context: interfaces.context.ContextInterface, + config_path: str, + requirement: interfaces.configuration.RequirementInterface, + progress_callback: constants.ProgressCallback = None, + ) -> None: + if requirement.unsatisfied(context, config_path): + if "pdbscan" not in context.symbol_space: + context.symbol_space.append( + native.NativeTable("pdbscan", native.std_ctypes) + ) + # TODO: check if this is a windows symbol requirement, otherwise ignore it + self._symbol_requirements = self.find_requirements( + context, config_path, requirement, requirements.SymbolTableRequirement + ) + potential_layers = self.find_virtual_layers_from_req( + context=context, config_path=config_path, requirement=requirement + ) + for sub_config_path, symbol_req in self._symbol_requirements: + parent_path = interfaces.configuration.parent_path(sub_config_path) + if symbol_req.unsatisfied(context, parent_path): + valid_kernel = self.determine_valid_kernel( + context, potential_layers, progress_callback + ) + if valid_kernel: + self.set_kernel_virtual_offset(context, valid_kernel) + self.recurse_symbol_fulfiller( + context, valid_kernel, progress_callback + ) + + if progress_callback is not None: + progress_callback(100, "PDB scanning finished") diff --git a/compose/local/arm64/windows.py b/compose/local/arm64/windows.py new file mode 100644 index 00000000..f7921dad --- /dev/null +++ b/compose/local/arm64/windows.py @@ -0,0 +1,565 @@ +# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 +# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 +# +"""Module to identify the Directory Table Base and architecture of windows +memory images. + +This module contains a PageMapScanner that scans a physical layer to identify self-referential pointers. +All windows versions include a self-referential pointer in their Directory Table Base's top table, in order to +have a single offset that will allow manipulation of the page tables themselves. + +In older windows version the self-referential pointer was at a specific fixed index within the table, +which was different for each architecture. In very recent Windows versions, the self-referential pointer +index has been randomized, so a different heuristic must be used. In these versions of windows it was found +that the physical offset for the DTB was always within the range of 0x1a0000 to 0x1b0000. As such, a search +for any self-referential pointer within these pages gives a high probability of being an accurate DTB. + +The self-referential indices for older versions of windows are listed below: + + +--------------+-------+ + | Architecture | Index | + +==============+=======+ + | x86 | 0x300 | + +--------------+-------+ + | PAE | 0x3 | + +--------------+-------+ + | x64 | 0x1ED | + +--------------+-------+ +""" +import json +import logging +import struct +from typing import Generator, Iterable, List, Optional, Tuple, Type + +from volatility3.framework import constants, interfaces +from volatility3.framework.configuration import requirements +from volatility3.framework.interfaces.configuration import path_join +from volatility3.framework.layers import arm, intel + +vollog = logging.getLogger(__name__) + + +class DtbSelfReferential: + """A generic DTB test which looks for a self-referential pointer at *any* + index within the page.""" + + def __init__( + self, + layer_type: Type[intel.Intel], + ptr_struct: str, + mask: int, + valid_range: Iterable[int], + reserved_bits: int, + ) -> None: + self.layer_type = layer_type + self.ptr_struct = ptr_struct + self.ptr_size = struct.calcsize(ptr_struct) + self.mask = mask + self.page_size: int = layer_type.page_size + self.valid_range = valid_range + self.reserved_bits = reserved_bits + + def __call__( + self, data: bytes, data_offset: int, page_offset: int + ) -> Optional[Tuple[int, int]]: + page = data[page_offset : page_offset + self.page_size] + if not page: + return None + ref_pages = set() + + for ref in range(0, self.page_size, self.ptr_size): + ptr_data = page[ref : ref + self.ptr_size] + (ptr,) = struct.unpack(self.ptr_struct, ptr_data) + # For both Intel-32e, bit 7 is reserved (more are reserved in PAE), so if that's ever set, + # we can move on + if (ptr & self.reserved_bits) and (ptr & 0x01): + return None + if ((ptr & self.mask) == (data_offset + page_offset)) and ( + data_offset + page_offset > 0 + ): + # Pointer must be valid + if ptr & 0x01: + ref_pages.add(ref) + + # The DTB is extremely unlikely to refer back to itself. so the number of reference should always be exactly 1 + if len(ref_pages) == 1: + ref_page = ref_pages.pop() + if (ref_page // self.ptr_size) in self.valid_range: + return (data_offset + page_offset), ref_page + return None + + +class DtbSelfRef32bit(DtbSelfReferential): + def __init__(self): + super().__init__( + layer_type=intel.WindowsIntel, + ptr_struct="I", + mask=0xFFFFF000, + valid_range=[0x300], + reserved_bits=0x0, + ) + + +class DtbSelfRef64bit(DtbSelfReferential): + def __init__(self) -> None: + super().__init__( + layer_type=intel.WindowsIntel32e, + ptr_struct="Q", + mask=0x3FFFFFFFFFF000, + valid_range=range(0x100, 0x1FF), + reserved_bits=0x80, + ) + + +class DtbSelfRef64bitOldWindows(DtbSelfReferential): + def __init__(self) -> None: + super().__init__( + layer_type=intel.WindowsIntel32e, + ptr_struct="Q", + mask=0x3FFFFFFFFFF000, + valid_range=[0x1ED], + reserved_bits=0x80, + ) + + +class DtbSelfRefPae(DtbSelfReferential): + def __init__(self) -> None: + super().__init__( + layer_type=intel.WindowsIntelPAE, + ptr_struct="Q", + valid_range=[0x3], + mask=0x3FFFFFFFFFF000, + reserved_bits=0x0, + ) + + @staticmethod + def _and_bytes(abytes, bbytes): + return bytes([a & b for a, b in zip(abytes[::-1], bbytes[::-1])][::-1]) + + def __call__( + self, data: bytes, data_offset: int, page_offset: int + ) -> Optional[Tuple[int, int]]: + dtb = super().__call__(data, data_offset, page_offset) + if dtb: + # Find the top page + top_pae_page = dtb[0] - 0x4000 + # The top page should map to the next four pages after it + # Build what we expect the page table to be + expected_table = b"".join( + [ + struct.pack( + self.ptr_struct, top_pae_page + (i * self.layer_type.page_size) + ) + for i in range(1, 5) + ] + ) + # Mask off the page bits of top level page map + page_table_mask = b"\x00\xf0\xff\xff\xff\xff\xff\xff" * 4 + page_table = data[ + top_pae_page + - data_offset : top_pae_page + - data_offset + + (4 * self.ptr_size) + ] + # Compare them + anded_bytes = self._and_bytes(page_table, page_table_mask) + if anded_bytes == expected_table: + return top_pae_page, dtb[1] + # Return None since the dtb value *isn't* None + return None + return dtb + + +class DtbSelfRef64bitAArch64(DtbSelfReferential): + def __init__(self) -> None: + """ + DTB was observed to be masked out with 0x60000000000000 (MiFillSystemPtes references ?), + but some pointers are also given upper bits masking on physical addresses. + HalpInterruptBuildGlobalStartupStub() kernel function allocates 0x28 bytes for the DTB. + """ + super().__init__( + layer_type=arm.WindowsAArch64, + ptr_struct="Q", + mask=(1 << 0x28) - 1 ^ arm.WindowsAArch64.page_mask, + valid_range=range(0x100, 0x300), + reserved_bits=0x0, + ) + + +class PageMapScanner(interfaces.layers.ScannerInterface): + """Scans through all pages using DTB tests to determine a dtb offset and + architecture.""" + + overlap = 0x4000 + thread_safe = True + tests = [DtbSelfRef64bit(), DtbSelfRefPae(), DtbSelfRef32bit()] + """The default tests to run when searching for DTBs""" + + def __init__(self, tests: Optional[List[DtbSelfReferential]]) -> None: + super().__init__() + if tests: + self.tests = tests + + def __call__( + self, data: bytes, data_offset: int + ) -> Generator[Tuple[DtbSelfReferential, int], None, None]: + for page_offset in range(0, len(data), 0x1000): + for test in self.tests: + result = test(data, data_offset, page_offset) + if result is not None: + yield (test, result[0]) + + +class WindowsIntelStacker(interfaces.automagic.StackerLayerInterface): + stack_order = 40 + exclusion_list = ["mac", "linux"] + + # Group these by region so we only run over the data once + test_sets = [ + # FIXME: Trying each architecture might take some (unnecessary) time ? + # FIXME: AArch64 was set on top, to speed-up tests + ( + "Detecting Self-referential pointer for AArch64 windows", + [DtbSelfRef64bitAArch64()], + # This offset was found by observations between memory samples : + # 0x800a9000, 0x80d45000, 0x80342800, 0x802a9800 + # It is also referenced in the Windows kernel. + # TODO: size is arbitrary for now + [(0x80000000, 0xF00000)], + ), + ( + "Detecting Self-referential pointer for recent windows", + [DtbSelfRef64bit()], + [(0x150000, 0x150000), (0x650000, 0xA0000)], + ), + ( + "Older windows fixed location self-referential pointers", + [DtbSelfRefPae(), DtbSelfRef32bit(), DtbSelfRef64bitOldWindows()], + [(0x30000, 0x1000000)], + ), + ] + + @classmethod + def stack( + cls, + context: interfaces.context.ContextInterface, + layer_name: str, + progress_callback: constants.ProgressCallback = None, + ) -> Optional[interfaces.layers.DataLayerInterface]: + """Attempts to determine and stack an intel layer on a physical layer + where possible. + + Where the DTB scan fails, it attempts a heuristic of checking + for the DTB within a specific range. New versions of windows, + with randomized self-referential pointers, appear to always load + their dtb within a small specific range (`0x1a0000` and + `0x1b0000`), so instead we scan for all self-referential + pointers in that range, and ignore any that contain multiple + self-references (since the DTB is very unlikely to point to + itself more than once). + """ + base_layer = context.layers[layer_name] + if isinstance(base_layer, intel.Intel) or isinstance(base_layer, arm.AArch64): + return None + if base_layer.metadata.get("os", None) not in ["Windows", "Unknown"]: + return None + layer = config_path = None + + # Check the metadata + if base_layer.metadata.get("os", None) == "Windows" and base_layer.metadata.get( + "page_map_offset" + ): + arch = base_layer.metadata.get("architecture", None) + if arch not in ["Intel32", "Intel64"]: + return None + # Set the layer type + layer_type: Type = intel.WindowsIntel + if arch == "Intel64": + layer_type = intel.WindowsIntel32e + elif base_layer.metadata.get("pae", False): + layer_type = intel.WindowsIntelPAE + # Construct the layer + new_layer_name = context.layers.free_layer_name("IntelLayer") + config_path = interfaces.configuration.path_join( + "IntelHelper", new_layer_name + ) + context.config[ + interfaces.configuration.path_join(config_path, "memory_layer") + ] = layer_name + context.config[ + interfaces.configuration.path_join(config_path, "page_map_offset") + ] = base_layer.metadata["page_map_offset"] + layer = layer_type( + context, + config_path=config_path, + name=new_layer_name, + metadata={"os": "Windows"}, + ) + page_map_offset = context.config[ + interfaces.configuration.path_join(config_path, "page_map_offset") + ] + vollog.debug(f"DTB was given to us by base layer: {hex(page_map_offset)}") + return layer + + # Self Referential finder + for description, tests, sections in cls.test_sets: + vollog.debug(description) + # There is a very high chance that the DTB will live in these very narrow segments, assuming we couldn't find them previously + hits: Generator[Tuple[DtbSelfReferential, int], None, None] = ( + base_layer.scan( + context, + PageMapScanner(tests=tests), + sections=sections, + progress_callback=progress_callback, + ) + ) + + # Flatten the generator + def sort_by_tests(x): + """Key used to sort by tests""" + return tests.index(x[0]), x[1] + + def get_max_pointer(page_table, test: DtbSelfReferential, ptr_size: int): + """Determines a pointer from a page_table""" + max_ptr = 0 + for index in range(0, len(page_table), ptr_size): + pointer = struct.unpack( + test.ptr_struct, page_table[index : index + ptr_size] + )[0] + # Mask out unnecessary (upper) bits, as done in DtbSelfReferential + # FIXME: prefer test.layer_type.page_mask, but attribute seems broken in Intel layer ("~" ?) + pointer &= test.mask ^ (test.layer_type.page_size - 1) + # Make sure the pointer is valid, ignore large pages which would require more calculation + if pointer & 0x1 and not pointer & test.reserved_bits: + max_ptr = max( + max_ptr, + (pointer ^ (pointer & 0xFFF)) + % ((1 << test.layer_type._maxvirtaddr) - 1), + ) + return max_ptr + + hits = sorted(list(hits), key=sort_by_tests) + + for test, page_map_offset in hits: + # Turn the page tables into integers and find the largest one + page_table = base_layer.read(page_map_offset, test.layer_type.page_size) + ptr_size = struct.calcsize(test.ptr_struct) + max_pointer = get_max_pointer(page_table, test, ptr_size) + + if max_pointer <= base_layer.maximum_address: + vollog.debug( + f"{test.__class__.__name__} test succeeded at {hex(page_map_offset)}" + ) + if issubclass(test.layer_type, intel.Intel): + new_layer_name = context.layers.free_layer_name("IntelLayer") + config_path = interfaces.configuration.path_join( + "IntelHelper", new_layer_name + ) + context.config[ + interfaces.configuration.path_join( + config_path, "memory_layer" + ) + ] = layer_name + context.config[ + interfaces.configuration.path_join( + config_path, "page_map_offset" + ) + ] = page_map_offset + layer = test.layer_type( + context, + config_path=config_path, + name=new_layer_name, + metadata={"os": "Windows"}, + ) + elif issubclass(test.layer_type, arm.AArch64): + cpu_registers = {} + # HalpStartupStub() kernel function offsets ttbr1_el1.baddr by 0x800 + # from ttbr0_el1.baddr + page_map_offset += 0x800 + new_layer_name = context.layers.free_layer_name("AArch64Layer") + config_path = interfaces.configuration.path_join( + "AArch64Helper", new_layer_name + ) + context.config[ + interfaces.configuration.path_join( + config_path, "memory_layer" + ) + ] = layer_name + context.config[ + interfaces.configuration.path_join( + config_path, "page_map_offset" + ) + ] = page_map_offset + ttbr1_el1 = arm.set_reg_bits( + page_map_offset, arm.AArch64RegMap.TTBR1_EL1.BADDR + ) + tcr_el1 = 0 + # MmSystemRangeStart = 0xFFFF800000000000 <=> T1SZ = 17 + tcr_el1 = arm.set_reg_bits( + 17, arm.AArch64RegMap.TCR_EL1.T1SZ, tcr_el1 + ) + tcr_el1 = arm.set_reg_bits( + 17, arm.AArch64RegMap.TCR_EL1.T0SZ, tcr_el1 + ) + # Page size is hardcoded in Windows kernel (CmSiGetPageSize() kernel function) + tcr_el1_tg1 = ( + arm.AArch64RegFieldValues._get_ttbr1_el1_granule_size( + 4, True + ) + ) + tcr_el1_tg0 = ( + arm.AArch64RegFieldValues._get_ttbr0_el1_granule_size( + 4, True + ) + ) + tcr_el1 = arm.set_reg_bits( + tcr_el1_tg1, arm.AArch64RegMap.TCR_EL1.TG1, tcr_el1 + ) + tcr_el1 = arm.set_reg_bits( + tcr_el1_tg0, arm.AArch64RegMap.TCR_EL1.TG0, tcr_el1 + ) + + cpu_registers[arm.AArch64RegMap.TCR_EL1.__name__] = tcr_el1 + cpu_registers[arm.AArch64RegMap.TTBR1_EL1.__name__] = ttbr1_el1 + context.config[path_join(config_path, "cpu_registers")] = ( + json.dumps(cpu_registers) + ) + + context.config[path_join(config_path, "entry_format")] = " {hex(base_layer.maximum_address)}" + ) + if layer is not None and config_path: + break + + if layer is not None and config_path: + vollog.debug( + "DTB was found at: 0x{:0x}".format( + context.config[ + interfaces.configuration.path_join( + config_path, "page_map_offset" + ) + ] + ) + ) + return layer + + +class WinSwapLayers(interfaces.automagic.AutomagicInterface): + """Class to read swap_layers filenames from single-swap-layers, create the + layers and populate the single-layers swap_layers.""" + + exclusion_list = ["linux", "mac"] + + def __call__( + self, + context: interfaces.context.ContextInterface, + config_path: str, + requirement: interfaces.configuration.RequirementInterface, + progress_callback: constants.ProgressCallback = None, + ) -> None: + """Finds translation layers that can have swap layers added.""" + + path_join = interfaces.configuration.path_join + self._translation_requirement = self.find_requirements( + context, + config_path, + requirement, + requirements.TranslationLayerRequirement, + shortcut=False, + ) + for trans_sub_config, trans_req in self._translation_requirement: + if not isinstance(trans_req, requirements.TranslationLayerRequirement): + # We need this so the type-checker knows we're a TranslationLayerRequirement + continue + swap_sub_config, swap_req = self.find_swap_requirement( + trans_sub_config, trans_req + ) + + counter = 0 + swap_config = interfaces.configuration.parent_path(swap_sub_config) + + if swap_req and swap_req.unsatisfied(context, swap_config): + # See if any of them need constructing + + for swap_location in self.config.get("single_swap_locations", []): + # Setup config locations/paths + current_layer_name = swap_req.name + str(counter) + current_layer_path = path_join(swap_sub_config, current_layer_name) + layer_loc_path = path_join(current_layer_path, "location") + layer_class_path = path_join(current_layer_path, "class") + counter += 1 + + # Fill in the config + if swap_location: + context.config[current_layer_path] = current_layer_name + try: + context.config[layer_loc_path] = ( + requirements.URIRequirement.location_from_file( + swap_location + ) + ) + except ValueError: + vollog.warning( + f"Volatility swap_location {swap_location} could not be validated - swap layer disabled" + ) + continue + context.config[layer_class_path] = ( + "volatility3.framework.layers.physical.FileLayer" + ) + + # Add the requirement + new_req = requirements.TranslationLayerRequirement( + name=current_layer_name, + description="Swap Layer", + optional=False, + ) + swap_req.add_requirement(new_req) + + context.config[path_join(swap_sub_config, "number_of_elements")] = ( + counter + ) + context.config[swap_sub_config] = True + + swap_req.construct(context, swap_config) + + @staticmethod + def find_swap_requirement( + config: str, requirement: requirements.TranslationLayerRequirement + ) -> Tuple[str, Optional[requirements.LayerListRequirement]]: + """Takes a Translation layer and returns its swap_layer requirement.""" + swap_req = None + for req_name in requirement.requirements: + req = requirement.requirements[req_name] + if ( + isinstance(req, requirements.LayerListRequirement) + and req.name == "swap_layers" + ): + swap_req = req + continue + + swap_config = interfaces.configuration.path_join(config, "swap_layers") + return swap_config, swap_req + + @classmethod + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: + """Returns the requirements of this plugin.""" + return [ + requirements.ListRequirement( + name="single_swap_locations", + element_type=str, + min_elements=0, + max_elements=16, + description="Specifies a list of swap layer URIs for use with single-location", + optional=True, + ) + ] diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index d94912b2..57887e89 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.7.1-py3.12 +FROM daskdev/dask:2024.8.1-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -27,7 +27,7 @@ RUN freshclam # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@f740146f692ba288f376a939b24b1c1a8f7cf5e2#egg=volatility3 \ +RUN pip install uv==0.3.5 -e git+https://github.com/dadokkio/volatility3.git@517f46e833648d1232b410436e53e07da429d6f5#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh @@ -37,8 +37,9 @@ COPY ./compose/local/dask/daskworkerinit.py /opt/daskworkerinit.py COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py #EXPERIMENTAL SUPPORT FOR ARM64 -COPY ./compose/local/linux.py /src/volatility3/volatility3/framework/automagic/linux.py -COPY ./compose/local/arm.py /src/volatility3/volatility3/framework/layers/arm.py +COPY ./compose/local/arm64/pdbscan.py /src/volatility3/volatility3/framework/automagic/pdbscan.py +COPY ./compose/local/arm64/windows.py /src/volatility3/volatility3/framework/automagic/windows.py +COPY ./compose/local/arm64/arm.py /src/volatility3/volatility3/framework/layers/arm.py RUN sed -i 's/\["Intel32", "Intel64"\]/\["Intel32", "Intel64", "AArch64"\]/g' /src/volatility3/volatility3/framework/plugins/linux/*.py RUN mkdir -p $local_folder /maxmind diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index ce323516..3f7f919e 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.4-slim-bookworm as common-base +FROM python:3.12.5-slim-bookworm as common-base ENV DJANGO_SETTINGS_MODULE config.settings.local ENV PYTHONUNBUFFERED 1 @@ -44,14 +44,15 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.2.31 -e git+https://github.com/dadokkio/volatility3.git@f740146f692ba288f376a939b24b1c1a8f7cf5e2#egg=volatility3 \ +RUN pip install uv==0.3.5 -e git+https://github.com/dadokkio/volatility3.git@517f46e833648d1232b410436e53e07da429d6f5#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py #EXPERIMENTAL SUPPORT FOR ARM64 -COPY ./compose/local/linux.py /src/volatility3/volatility3/framework/automagic/linux.py -COPY ./compose/local/arm.py /src/volatility3/volatility3/framework/layers/arm.py +COPY ./compose/local/arm64/pdbscan.py /src/volatility3/volatility3/framework/automagic/pdbscan.py +COPY ./compose/local/arm64/windows.py /src/volatility3/volatility3/framework/automagic/windows.py +COPY ./compose/local/arm64/arm.py /src/volatility3/volatility3/framework/layers/arm.py RUN sed -i 's/\["Intel32", "Intel64"\]/\["Intel32", "Intel64", "AArch64"\]/g' /src/volatility3/volatility3/framework/plugins/linux/*.py RUN mkdir -p $local_folder /maxmind diff --git a/compose/local/linux.py b/compose/local/linux.py deleted file mode 100644 index ec81c714..00000000 --- a/compose/local/linux.py +++ /dev/null @@ -1,412 +0,0 @@ -# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 -# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 -# - -import logging -import os -from typing import Optional, Tuple, Type, Union - -from volatility3.framework import constants, interfaces, exceptions -from volatility3.framework.automagic import symbol_cache, symbol_finder -from volatility3.framework.configuration import requirements -from volatility3.framework.layers import intel, scanners, arm -from volatility3.framework.symbols import linux - -vollog = logging.getLogger(__name__) - - -class LinuxStacker(interfaces.automagic.StackerLayerInterface): - stack_order = 35 - exclusion_list = ["mac", "windows"] - join = interfaces.configuration.path_join - - @classmethod - def stack( - cls, - context: interfaces.context.ContextInterface, - layer_name: str, - progress_callback: constants.ProgressCallback = None, - ) -> Optional[interfaces.layers.DataLayerInterface]: - """Attempts to identify linux within this layer.""" - # Version check the SQlite cache - required = (1, 0, 0) - if not requirements.VersionRequirement.matches_required( - required, symbol_cache.SqliteCache.version - ): - vollog.info( - f"SQLiteCache version not suitable: required {required} found {symbol_cache.SqliteCache.version}" - ) - return None - - # Bail out by default unless we can stack properly - layer = context.layers[layer_name] - - # Never stack on top of a linux layer - # FIXME: Find a way to improve this check - if isinstance(layer, intel.Intel) or isinstance(layer, arm.AArch64): - return None - - identifiers_path = os.path.join( - constants.CACHE_PATH, constants.IDENTIFIERS_FILENAME - ) - linux_banners = symbol_cache.SqliteCache( - identifiers_path - ).get_identifier_dictionary(operating_system="linux") - # If we have no banners, don't bother scanning - if not linux_banners: - vollog.info( - "No Linux banners found - if this is a linux plugin, please check your symbol files location" - ) - return None - - seen_banners = [] - mss = scanners.MultiStringScanner([x for x in linux_banners if x is not None]) - for _, banner in layer.scan( - context=context, scanner=mss, progress_callback=progress_callback - ): - # No need to try stackers on the same banner more than once - if banner in seen_banners: - continue - else: - seen_banners.append(banner) - - vollog.debug(f"Identified banner: {repr(banner)}") - - isf_path = linux_banners.get(banner, None) - if isf_path: - table_name = context.symbol_space.free_table_name("LinuxStacker") - table = linux.LinuxKernelIntermedSymbols( - context, - "temporary." + table_name, - name=table_name, - isf_url=isf_path, - ) - context.symbol_space.append(table) - new_layer_name = context.layers.free_layer_name("LinuxLayer") - config_path = cls.join("LinuxHelper", new_layer_name) - context.config[cls.join(config_path, "memory_layer")] = layer_name - context.config[ - cls.join(config_path, LinuxSymbolFinder.banner_config_key) - ] = str(banner, "latin-1") - - linux_arch_stackers = [cls.intel_stacker, cls.aarch64_stacker] - for linux_arch_stacker in linux_arch_stackers: - try: - layer = linux_arch_stacker( - context=context, - layer_name=layer_name, - table=table, - table_name=table_name, - config_path=config_path, - new_layer_name=new_layer_name, - banner=banner, - progress_callback=progress_callback, - ) - if layer: - return layer - except Exception as e: - vollog.exception(e) - - vollog.debug("No suitable linux banner could be matched") - return None - - @classmethod - def intel_stacker( - cls, - context: interfaces.context.ContextInterface, - layer_name: str, - table: linux.LinuxKernelIntermedSymbols, - table_name: str, - config_path: str, - new_layer_name: str, - banner: str, - progress_callback: constants.ProgressCallback = None, - ) -> Union[intel.Intel, intel.Intel32e, None]: - layer_class: Type = intel.Intel - if "init_top_pgt" in table.symbols: - layer_class = intel.Intel32e - dtb_symbol_name = "init_top_pgt" - elif "init_level4_pgt" in table.symbols: - layer_class = intel.Intel32e - dtb_symbol_name = "init_level4_pgt" - else: - dtb_symbol_name = "swapper_pg_dir" - - kaslr_shift, aslr_shift = cls.find_aslr( - context, - table_name, - layer_name, - layer_class, - progress_callback=progress_callback, - ) - - dtb = cls.virtual_to_physical_address( - table.get_symbol(dtb_symbol_name).address + kaslr_shift - ) - - # Build the new layer - context.config[cls.join(config_path, "page_map_offset")] = dtb - - layer = layer_class( - context, - config_path=config_path, - name=new_layer_name, - metadata={"os": "Linux"}, - ) - layer.config["kernel_virtual_offset"] = aslr_shift - linux_banner_address = table.get_symbol("linux_banner").address + aslr_shift - test_banner_equality = cls.verify_translation_by_banner( - context=context, - layer=layer, - layer_name=layer_name, - linux_banner_address=linux_banner_address, - target_banner=banner, - ) - - if layer and dtb and test_banner_equality: - vollog.debug(f"DTB was found at: 0x{dtb:0x}") - vollog.debug("Intel image found") - return layer - else: - layer.destroy() - - return None - - @classmethod - def aarch64_stacker( - cls, - context: interfaces.context.ContextInterface, - layer_name: str, - table: linux.LinuxKernelIntermedSymbols, - table_name: str, - config_path: str, - new_layer_name: str, - banner: bytes, - progress_callback: constants.ProgressCallback = None, - ) -> Optional[arm.AArch64]: - layer_class = arm.AArch64 - kaslr_shift, aslr_shift = cls.find_aslr( - context, - table_name, - layer_name, - layer_class, - progress_callback=progress_callback, - ) - dtb = table.get_symbol("swapper_pg_dir").address + kaslr_shift - context.config[cls.join(config_path, "page_map_offset")] = dtb - context.config[cls.join(config_path, "page_map_offset_kernel")] = dtb - kernel_endianness = table.get_type("pointer").vol.data_format.byteorder - context.config[cls.join(config_path, "kernel_endianness")] = kernel_endianness - - # CREDIT : https://github.com/crash-utility/crash/blob/28891d1127542dbb2d5ba16c575e14e741ed73ef/arm64.c#L941 - kernel_flags = 0 - if "_kernel_flags_le" in table.symbols: - kernel_flags = table.get_symbol("_kernel_flags_le").address - if "_kernel_flags_le_hi32" in table.symbols: - kernel_flags |= table.get_symbol("_kernel_flags_le_hi32").address << 32 - if "_kernel_flags_le_lo32" in table.symbols: - kernel_flags |= table.get_symbol("_kernel_flags_le_lo32").address - - # https://www.kernel.org/doc/Documentation/arm64/booting.txt - page_size_kernel_space_bit = (kernel_flags >> 1) & 3 - page_size_kernel_space_candidates = ( - [4**page_size_kernel_space_bit] - if 1 <= page_size_kernel_space_bit <= 3 - else [4, 16, 64] - ) - - linux_banner_address = table.get_symbol("linux_banner").address + aslr_shift - # Linux source : v6.7/source/arch/arm64/include/asm/memory.h#L186 - v5.7/source/arch/arm64/include/asm/memory.h#L160 - if "vabits_actual" in table.symbols: - vabits_actual_phys_addr = ( - table.get_symbol("vabits_actual").address + kaslr_shift - ) - # Linux source : v6.7/source/arch/arm64/Kconfig#L1263, VA_BITS - va_bits = int.from_bytes( - context.layers[layer_name].read(vabits_actual_phys_addr, 8), - kernel_endianness, - ) - else: - """ - Count leftmost bits equal to 1, deduce number of used bits for virtual addressing. - Example : - linux_banner_address = 0xffffffd733aae820 = 0b1111111111111111111111111101011100110011101010101110100000100000 - va_bits = (linux_banner_address ^ (2**64 - 1)).bit_length() + 1 = 39 - """ - va_bits = (linux_banner_address ^ (2**64 - 1)).bit_length() + 1 - - """ - Determining the number of useful bits in virtual addresses (VA_BITS) - is not straightforward, and not available in the kernel symbols. - Calculation by masking works great, but not in every case, due to the AArch64 memory layout, - sometimes pushing kernel addresses "too far" from the TTB1 start. - See https://www.kernel.org/doc/html/v5.5/arm64/memory.html. - Errors are by 1 or 2 bits, so we can try va_bits - {1,2,3}. - Example, assuming the good va_bits value is 39 : - # Case where calculation was correct : 1 iteration - va_bits_candidates = [**39**, 38, 37, 36] - # Case where calculation is off by 1 : 2 iterations - va_bits_candidates = [40, **39**, 38, 37] - """ - va_bits_candidates = [va_bits] + [va_bits + i for i in range(-1, -4, -1)] - for va_bits in va_bits_candidates: - tcr_el1_t1sz = 64 - va_bits - # T1SZ is considered equal to T0SZ - context.config[cls.join(config_path, "tcr_el1_t1sz")] = tcr_el1_t1sz - context.config[cls.join(config_path, "tcr_el1_t0sz")] = tcr_el1_t1sz - - # If "_kernel_flags_le*" aren't in the symbols, we can still do a quick bruteforce on [4,16,64] page sizes - # False positives cannot happen, as translation indexes will be off on a wrong page size - for page_size_kernel_space in page_size_kernel_space_candidates: - # Kernel space page size is considered equal to the user space page size - context.config[cls.join(config_path, "page_size_kernel_space")] = ( - page_size_kernel_space - ) - context.config[cls.join(config_path, "page_size_user_space")] = ( - page_size_kernel_space - ) - # Build layer - layer = layer_class( - context, - config_path=config_path, - name=new_layer_name, - metadata={"os": "Linux"}, - ) - layer.config["kernel_virtual_offset"] = aslr_shift - - test_banner_equality = cls.verify_translation_by_banner( - context=context, - layer=layer, - layer_name=layer_name, - linux_banner_address=linux_banner_address, - target_banner=banner, - ) - - if layer and dtb and test_banner_equality: - vollog.debug(f"Kernel DTB was found at: 0x{dtb:0x}") - vollog.debug("AArch64 image found") - return layer - else: - layer.destroy() - - return None - - @classmethod - def verify_translation_by_banner( - cls, - context: interfaces.context.ContextInterface, - layer, - layer_name: str, - linux_banner_address: int, - target_banner: bytes, - ) -> bool: - """Determine if a stacked layer is correct or a false positive, by calling the underlying - _translate method against the linux_banner symbol virtual address. Then, compare it with - the detected banner to verify the correct translation. - """ - - try: - banner_phys_address = layer._translate(linux_banner_address)[0] - banner_value = context.layers[layer_name].read( - banner_phys_address, len(target_banner) - ) - except exceptions.InvalidAddressException as e: - vollog.log( - constants.LOGLEVEL_VVVV, - 'Cannot translate "linux_banner" symbol virtual address.', - ) - return False - - if not banner_value == target_banner: - vollog.error( - f"Mismatch between scanned and virtually translated linux banner : {target_banner} != {banner_value}." - ) - return False - - return True - - @classmethod - def find_aslr( - cls, - context: interfaces.context.ContextInterface, - symbol_table: str, - layer_name: str, - layer_class, - progress_callback: constants.ProgressCallback = None, - ) -> Tuple[int, int]: - """Determines the offset of the actual DTB in physical space and its - symbol offset.""" - init_task_symbol = symbol_table + constants.BANG + "init_task" - init_task_json_address = context.symbol_space.get_symbol( - init_task_symbol - ).address - swapper_signature = rb"swapper(\/0|\x00\x00)\x00\x00\x00\x00\x00\x00" - module = context.module(symbol_table, layer_name, 0) - address_mask = context.symbol_space[symbol_table].config.get( - "symbol_mask", None - ) - - task_symbol = module.get_type("task_struct") - comm_child_offset = task_symbol.relative_child_offset("comm") - - for offset in context.layers[layer_name].scan( - scanner=scanners.RegExScanner(swapper_signature), - context=context, - progress_callback=progress_callback, - ): - init_task_address = offset - comm_child_offset - init_task = module.object( - object_type="task_struct", offset=init_task_address, absolute=True - ) - if init_task.pid != 0: - continue - elif ( - init_task.has_member("state") - and init_task.state.cast("unsigned int") != 0 - ): - continue - - # This we get for free - aslr_shift = ( - init_task.files.cast("long unsigned int") - - module.get_symbol("init_files").address - ) - if layer_class == arm.AArch64: - kaslr_shift = init_task_address - init_task_json_address - else: - kaslr_shift = init_task_address - cls.virtual_to_physical_address( - init_task_json_address - ) - if address_mask: - aslr_shift = aslr_shift & address_mask - - if aslr_shift & 0xFFF != 0 or kaslr_shift & 0xFFF != 0: - continue - vollog.debug( - "Linux ASLR shift values determined: physical {:0x} virtual {:0x}".format( - kaslr_shift, aslr_shift - ) - ) - return kaslr_shift, aslr_shift - - # We don't throw an exception, because we may legitimately not have an ASLR shift, but we report it - vollog.debug("Scanners could not determine any ASLR shifts, using 0 for both") - return 0, 0 - - @classmethod - def virtual_to_physical_address(cls, addr: int) -> int: - """Converts a virtual linux address to a physical one (does not account - of ASLR)""" - if addr > 0xFFFFFFFF80000000: - return addr - 0xFFFFFFFF80000000 - return addr - 0xC0000000 - - -class LinuxSymbolFinder(symbol_finder.SymbolFinder): - """Linux symbol loader based on uname signature strings.""" - - banner_config_key = "kernel_banner" - operating_system = "linux" - symbol_class = "volatility3.framework.symbols.linux.LinuxKernelIntermedSymbols" - find_aslr = lambda cls, *args: LinuxStacker.find_aslr(*args)[1] - exclusion_list = ["mac", "windows"] diff --git a/config/settings/base.py b/config/settings/base.py index f5449e5e..5be8adc5 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -252,7 +252,7 @@ ACCOUNT_ADAPTER = "allauth.account.adapter.DefaultAccountAdapter" MFA_SUPPORTED_TYPES = ["totp", "webauthn"] -MFA_PASSKEY_LOGIN_ENABLED = True +MFA_PASSKEY_LOGIN_ENABLED = False MFA_WEBAUTHN_ALLOW_INSECURE_ORIGIN = True # Elasticsearch diff --git a/orochi/static/README.txt b/orochi/static/README.txt index 51fe47c7..06a1a700 100644 --- a/orochi/static/README.txt +++ b/orochi/static/README.txt @@ -1,10 +1,10 @@ # Bootstrap [MAIN CSS] --> https://getbootstrap.com/ ---> version 5.3.2 +--> version 5.3.3 # Fontawesome [ICON] --> https://fontawesome.com/ ---> version 6.4.2 +--> version 6.6.0 # diff_view [COMPARE 2 PLUGIN RESULT] --> https://benjamine.github.io/jsondiffpatch/demo/index.html @@ -12,7 +12,7 @@ # jsonedit [VIEW JSON FILE, eg. HIVE] --> https://github.com/josdejong/jsoneditor/tree/master ---> version 9.10.3 +--> version 10.1.0 # toast [NOTIFICATION] --> https://github.com/Script47/Toast @@ -24,20 +24,20 @@ # wunderbaum [TREE VIEW FOR PSTREE] --> https://github.com/mar10/wunderbaum/ ---> version 0.8.2 +--> version 0.11.0 # Datatables [TABLE RENDERING] --> https://datatables.net/ ---> version 1.13.1 +--> version 2.1.4 --> with Bootstrap5 template # Datatables checkbox --> https://github.com/gyrocode/jquery-datatables-checkboxes ---> version: 1.2.13 +--> version: 1.3.0 # Jscolor [COLOR PICKER] --> http://jscolor.com ---> version 2.5.1 +--> version 2.5.2 # Keyrune [MTG icons] --> https://github.com/andrewgioia/keyrune @@ -45,7 +45,7 @@ # Marked [Changelog with MD] --> https://github.com/markedjs/marked ---> version 9.1.1 +--> version 14.1.0 # Handlebars [Template rendering] --> https://handlebarsjs.com/ diff --git a/orochi/static/css/bootstrap/bootstrap.min.css b/orochi/static/css/bootstrap/bootstrap.min.css index e856c100..46dc7faa 100644 --- a/orochi/static/css/bootstrap/bootstrap.min.css +++ b/orochi/static/css/bootstrap/bootstrap.min.css @@ -1,6 +1,6 @@ @charset "UTF-8";/*! - * Bootstrap v5.3.2 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color:#86b7fe;--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} + */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--bs-offcanvas-padding-y)) calc(-.5 * var(--bs-offcanvas-padding-x)) calc(-.5 * var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} /*# sourceMappingURL=bootstrap.min.css.map */ diff --git a/orochi/static/css/bootstrap/bootstrap.min.css.map b/orochi/static/css/bootstrap/bootstrap.min.css.map index d0b28dbb..b6b6d563 100644 --- a/orochi/static/css/bootstrap/bootstrap.min.css.map +++ b/orochi/static/css/bootstrap/bootstrap.min.css.map @@ -1,120 +1 @@ -{ - "version": 3, - "sources": [ - "../../scss/mixins/_banner.scss", - "../../scss/_root.scss", - "dist/css/bootstrap.css", - "../../scss/vendor/_rfs.scss", - "../../scss/mixins/_color-mode.scss", - "../../scss/_reboot.scss", - "../../scss/mixins/_border-radius.scss", - "../../scss/_type.scss", - "../../scss/mixins/_lists.scss", - "../../scss/_images.scss", - "../../scss/mixins/_image.scss", - "../../scss/_containers.scss", - "../../scss/mixins/_container.scss", - "../../scss/mixins/_breakpoints.scss", - "../../scss/_grid.scss", - "../../scss/mixins/_grid.scss", - "../../scss/_tables.scss", - "../../scss/mixins/_table-variants.scss", - "../../scss/forms/_labels.scss", - "../../scss/forms/_form-text.scss", - "../../scss/forms/_form-control.scss", - "../../scss/mixins/_transition.scss", - "../../scss/mixins/_gradients.scss", - "../../scss/forms/_form-select.scss", - "../../scss/forms/_form-check.scss", - "../../scss/forms/_form-range.scss", - "../../scss/forms/_floating-labels.scss", - "../../scss/forms/_input-group.scss", - "../../scss/mixins/_forms.scss", - "../../scss/_buttons.scss", - "../../scss/mixins/_buttons.scss", - "../../scss/_transitions.scss", - "../../scss/_dropdown.scss", - "../../scss/mixins/_caret.scss", - "../../scss/_button-group.scss", - "../../scss/_nav.scss", - "../../scss/_navbar.scss", - "../../scss/_card.scss", - "../../scss/_accordion.scss", - "../../scss/_breadcrumb.scss", - "../../scss/_pagination.scss", - "../../scss/mixins/_pagination.scss", - "../../scss/_badge.scss", - "../../scss/_alert.scss", - "../../scss/_progress.scss", - "../../scss/_list-group.scss", - "../../scss/_close.scss", - "../../scss/_toasts.scss", - "../../scss/_modal.scss", - "../../scss/mixins/_backdrop.scss", - "../../scss/_tooltip.scss", - "../../scss/mixins/_reset-text.scss", - "../../scss/_popover.scss", - "../../scss/_carousel.scss", - "../../scss/mixins/_clearfix.scss", - "../../scss/_spinners.scss", - "../../scss/_offcanvas.scss", - "../../scss/_placeholders.scss", - "../../scss/helpers/_color-bg.scss", - "../../scss/helpers/_colored-links.scss", - "../../scss/helpers/_focus-ring.scss", - "../../scss/helpers/_icon-link.scss", - "../../scss/helpers/_ratio.scss", - "../../scss/helpers/_position.scss", - "../../scss/helpers/_stacks.scss", - "../../scss/helpers/_visually-hidden.scss", - "../../scss/mixins/_visually-hidden.scss", - "../../scss/helpers/_stretched-link.scss", - "../../scss/helpers/_text-truncation.scss", - "../../scss/mixins/_text-truncate.scss", - "../../scss/helpers/_vr.scss", - "../../scss/mixins/_utilities.scss", - "../../scss/utilities/_api.scss" - ], - "names": [], - "mappings": "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", - "sourcesContent": [ - "@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.3.2 (https://getbootstrap.com/)\n * Copyright 2011-2023 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n", - ":root,\n[data-bs-theme=\"light\"] {\n // Note: Custom variable values only support SassScript inside `#{}`.\n\n // Colors\n //\n // Generate palettes for full colors, grays, and theme colors.\n\n @each $color, $value in $colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $grays {\n --#{$prefix}gray-#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors-rgb {\n --#{$prefix}#{$color}-rgb: #{$value};\n }\n\n @each $color, $value in $theme-colors-text {\n --#{$prefix}#{$color}-text-emphasis: #{$value};\n }\n\n @each $color, $value in $theme-colors-bg-subtle {\n --#{$prefix}#{$color}-bg-subtle: #{$value};\n }\n\n @each $color, $value in $theme-colors-border-subtle {\n --#{$prefix}#{$color}-border-subtle: #{$value};\n }\n\n --#{$prefix}white-rgb: #{to-rgb($white)};\n --#{$prefix}black-rgb: #{to-rgb($black)};\n\n // Fonts\n\n // Note: Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)};\n --#{$prefix}font-monospace: #{inspect($font-family-monospace)};\n --#{$prefix}gradient: #{$gradient};\n\n // Root and body\n // scss-docs-start root-body-variables\n @if $font-size-root != null {\n --#{$prefix}root-font-size: #{$font-size-root};\n }\n --#{$prefix}body-font-family: #{inspect($font-family-base)};\n @include rfs($font-size-base, --#{$prefix}body-font-size);\n --#{$prefix}body-font-weight: #{$font-weight-base};\n --#{$prefix}body-line-height: #{$line-height-base};\n @if $body-text-align != null {\n --#{$prefix}body-text-align: #{$body-text-align};\n }\n\n --#{$prefix}body-color: #{$body-color};\n --#{$prefix}body-color-rgb: #{to-rgb($body-color)};\n --#{$prefix}body-bg: #{$body-bg};\n --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\n\n --#{$prefix}emphasis-color: #{$body-emphasis-color};\n --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)};\n\n --#{$prefix}secondary-color: #{$body-secondary-color};\n --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};\n --#{$prefix}secondary-bg: #{$body-secondary-bg};\n --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};\n\n --#{$prefix}tertiary-color: #{$body-tertiary-color};\n --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};\n --#{$prefix}tertiary-bg: #{$body-tertiary-bg};\n --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};\n // scss-docs-end root-body-variables\n\n --#{$prefix}heading-color: #{$headings-color};\n\n --#{$prefix}link-color: #{$link-color};\n --#{$prefix}link-color-rgb: #{to-rgb($link-color)};\n --#{$prefix}link-decoration: #{$link-decoration};\n\n --#{$prefix}link-hover-color: #{$link-hover-color};\n --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)};\n\n @if $link-hover-decoration != null {\n --#{$prefix}link-hover-decoration: #{$link-hover-decoration};\n }\n\n --#{$prefix}code-color: #{$code-color};\n --#{$prefix}highlight-color: #{$mark-color};\n --#{$prefix}highlight-bg: #{$mark-bg};\n\n // scss-docs-start root-border-var\n --#{$prefix}border-width: #{$border-width};\n --#{$prefix}border-style: #{$border-style};\n --#{$prefix}border-color: #{$border-color};\n --#{$prefix}border-color-translucent: #{$border-color-translucent};\n\n --#{$prefix}border-radius: #{$border-radius};\n --#{$prefix}border-radius-sm: #{$border-radius-sm};\n --#{$prefix}border-radius-lg: #{$border-radius-lg};\n --#{$prefix}border-radius-xl: #{$border-radius-xl};\n --#{$prefix}border-radius-xxl: #{$border-radius-xxl};\n --#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency\n --#{$prefix}border-radius-pill: #{$border-radius-pill};\n // scss-docs-end root-border-var\n\n --#{$prefix}box-shadow: #{$box-shadow};\n --#{$prefix}box-shadow-sm: #{$box-shadow-sm};\n --#{$prefix}box-shadow-lg: #{$box-shadow-lg};\n --#{$prefix}box-shadow-inset: #{$box-shadow-inset};\n\n // Focus styles\n // scss-docs-start root-focus-variables\n --#{$prefix}focus-ring-width: #{$focus-ring-width};\n --#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};\n --#{$prefix}focus-ring-color: #{$focus-ring-color};\n // scss-docs-end root-focus-variables\n\n // scss-docs-start root-form-validation-variables\n --#{$prefix}form-valid-color: #{$form-valid-color};\n --#{$prefix}form-valid-border-color: #{$form-valid-border-color};\n --#{$prefix}form-invalid-color: #{$form-invalid-color};\n --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};\n // scss-docs-end root-form-validation-variables\n}\n\n@if $enable-dark-mode {\n @include color-mode(dark, true) {\n color-scheme: dark;\n\n // scss-docs-start root-dark-mode-vars\n --#{$prefix}body-color: #{$body-color-dark};\n --#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)};\n --#{$prefix}body-bg: #{$body-bg-dark};\n --#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)};\n\n --#{$prefix}emphasis-color: #{$body-emphasis-color-dark};\n --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)};\n\n --#{$prefix}secondary-color: #{$body-secondary-color-dark};\n --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)};\n --#{$prefix}secondary-bg: #{$body-secondary-bg-dark};\n --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)};\n\n --#{$prefix}tertiary-color: #{$body-tertiary-color-dark};\n --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)};\n --#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark};\n --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)};\n\n @each $color, $value in $theme-colors-text-dark {\n --#{$prefix}#{$color}-text-emphasis: #{$value};\n }\n\n @each $color, $value in $theme-colors-bg-subtle-dark {\n --#{$prefix}#{$color}-bg-subtle: #{$value};\n }\n\n @each $color, $value in $theme-colors-border-subtle-dark {\n --#{$prefix}#{$color}-border-subtle: #{$value};\n }\n\n --#{$prefix}heading-color: #{$headings-color-dark};\n\n --#{$prefix}link-color: #{$link-color-dark};\n --#{$prefix}link-hover-color: #{$link-hover-color-dark};\n --#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)};\n --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)};\n\n --#{$prefix}code-color: #{$code-color-dark};\n --#{$prefix}highlight-color: #{$mark-color-dark};\n --#{$prefix}highlight-bg: #{$mark-bg-dark};\n\n --#{$prefix}border-color: #{$border-color-dark};\n --#{$prefix}border-color-translucent: #{$border-color-translucent-dark};\n\n --#{$prefix}form-valid-color: #{$form-valid-color-dark};\n --#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark};\n --#{$prefix}form-invalid-color: #{$form-invalid-color-dark};\n --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark};\n // scss-docs-end root-dark-mode-vars\n }\n}\n", - "@charset \"UTF-8\";\n/*!\n * Bootstrap v5.3.2 (https://getbootstrap.com/)\n * Copyright 2011-2023 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n:root,\n[data-bs-theme=light] {\n --bs-blue: #0d6efd;\n --bs-indigo: #6610f2;\n --bs-purple: #6f42c1;\n --bs-pink: #d63384;\n --bs-red: #dc3545;\n --bs-orange: #fd7e14;\n --bs-yellow: #ffc107;\n --bs-green: #198754;\n --bs-teal: #20c997;\n --bs-cyan: #0dcaf0;\n --bs-black: #000;\n --bs-white: #fff;\n --bs-gray: #6c757d;\n --bs-gray-dark: #343a40;\n --bs-gray-100: #f8f9fa;\n --bs-gray-200: #e9ecef;\n --bs-gray-300: #dee2e6;\n --bs-gray-400: #ced4da;\n --bs-gray-500: #adb5bd;\n --bs-gray-600: #6c757d;\n --bs-gray-700: #495057;\n --bs-gray-800: #343a40;\n --bs-gray-900: #212529;\n --bs-primary: #0d6efd;\n --bs-secondary: #6c757d;\n --bs-success: #198754;\n --bs-info: #0dcaf0;\n --bs-warning: #ffc107;\n --bs-danger: #dc3545;\n --bs-light: #f8f9fa;\n --bs-dark: #212529;\n --bs-primary-rgb: 13, 110, 253;\n --bs-secondary-rgb: 108, 117, 125;\n --bs-success-rgb: 25, 135, 84;\n --bs-info-rgb: 13, 202, 240;\n --bs-warning-rgb: 255, 193, 7;\n --bs-danger-rgb: 220, 53, 69;\n --bs-light-rgb: 248, 249, 250;\n --bs-dark-rgb: 33, 37, 41;\n --bs-primary-text-emphasis: #052c65;\n --bs-secondary-text-emphasis: #2b2f32;\n --bs-success-text-emphasis: #0a3622;\n --bs-info-text-emphasis: #055160;\n --bs-warning-text-emphasis: #664d03;\n --bs-danger-text-emphasis: #58151c;\n --bs-light-text-emphasis: #495057;\n --bs-dark-text-emphasis: #495057;\n --bs-primary-bg-subtle: #cfe2ff;\n --bs-secondary-bg-subtle: #e2e3e5;\n --bs-success-bg-subtle: #d1e7dd;\n --bs-info-bg-subtle: #cff4fc;\n --bs-warning-bg-subtle: #fff3cd;\n --bs-danger-bg-subtle: #f8d7da;\n --bs-light-bg-subtle: #fcfcfd;\n --bs-dark-bg-subtle: #ced4da;\n --bs-primary-border-subtle: #9ec5fe;\n --bs-secondary-border-subtle: #c4c8cb;\n --bs-success-border-subtle: #a3cfbb;\n --bs-info-border-subtle: #9eeaf9;\n --bs-warning-border-subtle: #ffe69c;\n --bs-danger-border-subtle: #f1aeb5;\n --bs-light-border-subtle: #e9ecef;\n --bs-dark-border-subtle: #adb5bd;\n --bs-white-rgb: 255, 255, 255;\n --bs-black-rgb: 0, 0, 0;\n --bs-font-sans-serif: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));\n --bs-body-font-family: var(--bs-font-sans-serif);\n --bs-body-font-size: 1rem;\n --bs-body-font-weight: 400;\n --bs-body-line-height: 1.5;\n --bs-body-color: #212529;\n --bs-body-color-rgb: 33, 37, 41;\n --bs-body-bg: #fff;\n --bs-body-bg-rgb: 255, 255, 255;\n --bs-emphasis-color: #000;\n --bs-emphasis-color-rgb: 0, 0, 0;\n --bs-secondary-color: rgba(33, 37, 41, 0.75);\n --bs-secondary-color-rgb: 33, 37, 41;\n --bs-secondary-bg: #e9ecef;\n --bs-secondary-bg-rgb: 233, 236, 239;\n --bs-tertiary-color: rgba(33, 37, 41, 0.5);\n --bs-tertiary-color-rgb: 33, 37, 41;\n --bs-tertiary-bg: #f8f9fa;\n --bs-tertiary-bg-rgb: 248, 249, 250;\n --bs-heading-color: inherit;\n --bs-link-color: #0d6efd;\n --bs-link-color-rgb: 13, 110, 253;\n --bs-link-decoration: underline;\n --bs-link-hover-color: #0a58ca;\n --bs-link-hover-color-rgb: 10, 88, 202;\n --bs-code-color: #d63384;\n --bs-highlight-color: #212529;\n --bs-highlight-bg: #fff3cd;\n --bs-border-width: 1px;\n --bs-border-style: solid;\n --bs-border-color: #dee2e6;\n --bs-border-color-translucent: rgba(0, 0, 0, 0.175);\n --bs-border-radius: 0.375rem;\n --bs-border-radius-sm: 0.25rem;\n --bs-border-radius-lg: 0.5rem;\n --bs-border-radius-xl: 1rem;\n --bs-border-radius-xxl: 2rem;\n --bs-border-radius-2xl: var(--bs-border-radius-xxl);\n --bs-border-radius-pill: 50rem;\n --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);\n --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);\n --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);\n --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);\n --bs-focus-ring-width: 0.25rem;\n --bs-focus-ring-opacity: 0.25;\n --bs-focus-ring-color: rgba(13, 110, 253, 0.25);\n --bs-form-valid-color: #198754;\n --bs-form-valid-border-color: #198754;\n --bs-form-invalid-color: #dc3545;\n --bs-form-invalid-border-color: #dc3545;\n}\n\n[data-bs-theme=dark] {\n color-scheme: dark;\n --bs-body-color: #dee2e6;\n --bs-body-color-rgb: 222, 226, 230;\n --bs-body-bg: #212529;\n --bs-body-bg-rgb: 33, 37, 41;\n --bs-emphasis-color: #fff;\n --bs-emphasis-color-rgb: 255, 255, 255;\n --bs-secondary-color: rgba(222, 226, 230, 0.75);\n --bs-secondary-color-rgb: 222, 226, 230;\n --bs-secondary-bg: #343a40;\n --bs-secondary-bg-rgb: 52, 58, 64;\n --bs-tertiary-color: rgba(222, 226, 230, 0.5);\n --bs-tertiary-color-rgb: 222, 226, 230;\n --bs-tertiary-bg: #2b3035;\n --bs-tertiary-bg-rgb: 43, 48, 53;\n --bs-primary-text-emphasis: #6ea8fe;\n --bs-secondary-text-emphasis: #a7acb1;\n --bs-success-text-emphasis: #75b798;\n --bs-info-text-emphasis: #6edff6;\n --bs-warning-text-emphasis: #ffda6a;\n --bs-danger-text-emphasis: #ea868f;\n --bs-light-text-emphasis: #f8f9fa;\n --bs-dark-text-emphasis: #dee2e6;\n --bs-primary-bg-subtle: #031633;\n --bs-secondary-bg-subtle: #161719;\n --bs-success-bg-subtle: #051b11;\n --bs-info-bg-subtle: #032830;\n --bs-warning-bg-subtle: #332701;\n --bs-danger-bg-subtle: #2c0b0e;\n --bs-light-bg-subtle: #343a40;\n --bs-dark-bg-subtle: #1a1d20;\n --bs-primary-border-subtle: #084298;\n --bs-secondary-border-subtle: #41464b;\n --bs-success-border-subtle: #0f5132;\n --bs-info-border-subtle: #087990;\n --bs-warning-border-subtle: #997404;\n --bs-danger-border-subtle: #842029;\n --bs-light-border-subtle: #495057;\n --bs-dark-border-subtle: #343a40;\n --bs-heading-color: inherit;\n --bs-link-color: #6ea8fe;\n --bs-link-hover-color: #8bb9fe;\n --bs-link-color-rgb: 110, 168, 254;\n --bs-link-hover-color-rgb: 139, 185, 254;\n --bs-code-color: #e685b5;\n --bs-highlight-color: #dee2e6;\n --bs-highlight-bg: #664d03;\n --bs-border-color: #495057;\n --bs-border-color-translucent: rgba(255, 255, 255, 0.15);\n --bs-form-valid-color: #75b798;\n --bs-form-valid-border-color: #75b798;\n --bs-form-invalid-color: #ea868f;\n --bs-form-invalid-border-color: #ea868f;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n :root {\n scroll-behavior: smooth;\n }\n}\n\nbody {\n margin: 0;\n font-family: var(--bs-body-font-family);\n font-size: var(--bs-body-font-size);\n font-weight: var(--bs-body-font-weight);\n line-height: var(--bs-body-line-height);\n color: var(--bs-body-color);\n text-align: var(--bs-body-text-align);\n background-color: var(--bs-body-bg);\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nhr {\n margin: 1rem 0;\n color: inherit;\n border: 0;\n border-top: var(--bs-border-width) solid;\n opacity: 0.25;\n}\n\nh6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n font-weight: 500;\n line-height: 1.2;\n color: var(--bs-heading-color);\n}\n\nh1, .h1 {\n font-size: calc(1.375rem + 1.5vw);\n}\n@media (min-width: 1200px) {\n h1, .h1 {\n font-size: 2.5rem;\n }\n}\n\nh2, .h2 {\n font-size: calc(1.325rem + 0.9vw);\n}\n@media (min-width: 1200px) {\n h2, .h2 {\n font-size: 2rem;\n }\n}\n\nh3, .h3 {\n font-size: calc(1.3rem + 0.6vw);\n}\n@media (min-width: 1200px) {\n h3, .h3 {\n font-size: 1.75rem;\n }\n}\n\nh4, .h4 {\n font-size: calc(1.275rem + 0.3vw);\n}\n@media (min-width: 1200px) {\n h4, .h4 {\n font-size: 1.5rem;\n }\n}\n\nh5, .h5 {\n font-size: 1.25rem;\n}\n\nh6, .h6 {\n font-size: 1rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title] {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n cursor: help;\n -webkit-text-decoration-skip-ink: none;\n text-decoration-skip-ink: none;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: 0.5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall, .small {\n font-size: 0.875em;\n}\n\nmark, .mark {\n padding: 0.1875em;\n color: var(--bs-highlight-color);\n background-color: var(--bs-highlight-bg);\n}\n\nsub,\nsup {\n position: relative;\n font-size: 0.75em;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\na {\n color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));\n text-decoration: underline;\n}\na:hover {\n --bs-link-color-rgb: var(--bs-link-hover-color-rgb);\n}\n\na:not([href]):not([class]), a:not([href]):not([class]):hover {\n color: inherit;\n text-decoration: none;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: var(--bs-font-monospace);\n font-size: 1em;\n}\n\npre {\n display: block;\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n font-size: 0.875em;\n}\npre code {\n font-size: inherit;\n color: inherit;\n word-break: normal;\n}\n\ncode {\n font-size: 0.875em;\n color: var(--bs-code-color);\n word-wrap: break-word;\n}\na > code {\n color: inherit;\n}\n\nkbd {\n padding: 0.1875rem 0.375rem;\n font-size: 0.875em;\n color: var(--bs-body-bg);\n background-color: var(--bs-body-color);\n border-radius: 0.25rem;\n}\nkbd kbd {\n padding: 0;\n font-size: 1em;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n color: var(--bs-secondary-color);\n text-align: left;\n}\n\nth {\n text-align: inherit;\n text-align: -webkit-match-parent;\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\nlabel {\n display: inline-block;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\n[role=button] {\n cursor: pointer;\n}\n\nselect {\n word-wrap: normal;\n}\nselect:disabled {\n opacity: 1;\n}\n\n[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {\n display: none !important;\n}\n\nbutton,\n[type=button],\n[type=reset],\n[type=submit] {\n -webkit-appearance: button;\n}\nbutton:not(:disabled),\n[type=button]:not(:disabled),\n[type=reset]:not(:disabled),\n[type=submit]:not(:disabled) {\n cursor: pointer;\n}\n\n::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ntextarea {\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n float: left;\n width: 100%;\n padding: 0;\n margin-bottom: 0.5rem;\n font-size: calc(1.275rem + 0.3vw);\n line-height: inherit;\n}\n@media (min-width: 1200px) {\n legend {\n font-size: 1.5rem;\n }\n}\nlegend + * {\n clear: left;\n}\n\n::-webkit-datetime-edit-fields-wrapper,\n::-webkit-datetime-edit-text,\n::-webkit-datetime-edit-minute,\n::-webkit-datetime-edit-hour-field,\n::-webkit-datetime-edit-day-field,\n::-webkit-datetime-edit-month-field,\n::-webkit-datetime-edit-year-field {\n padding: 0;\n}\n\n::-webkit-inner-spin-button {\n height: auto;\n}\n\n[type=search] {\n -webkit-appearance: textfield;\n outline-offset: -2px;\n}\n\n/* rtl:raw:\n[type=\"tel\"],\n[type=\"url\"],\n[type=\"email\"],\n[type=\"number\"] {\n direction: ltr;\n}\n*/\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\n::file-selector-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\niframe {\n border: 0;\n}\n\nsummary {\n display: list-item;\n cursor: pointer;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.lead {\n font-size: 1.25rem;\n font-weight: 300;\n}\n\n.display-1 {\n font-size: calc(1.625rem + 4.5vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-1 {\n font-size: 5rem;\n }\n}\n\n.display-2 {\n font-size: calc(1.575rem + 3.9vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-2 {\n font-size: 4.5rem;\n }\n}\n\n.display-3 {\n font-size: calc(1.525rem + 3.3vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-3 {\n font-size: 4rem;\n }\n}\n\n.display-4 {\n font-size: calc(1.475rem + 2.7vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-4 {\n font-size: 3.5rem;\n }\n}\n\n.display-5 {\n font-size: calc(1.425rem + 2.1vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-5 {\n font-size: 3rem;\n }\n}\n\n.display-6 {\n font-size: calc(1.375rem + 1.5vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-6 {\n font-size: 2.5rem;\n }\n}\n\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline-item {\n display: inline-block;\n}\n.list-inline-item:not(:last-child) {\n margin-right: 0.5rem;\n}\n\n.initialism {\n font-size: 0.875em;\n text-transform: uppercase;\n}\n\n.blockquote {\n margin-bottom: 1rem;\n font-size: 1.25rem;\n}\n.blockquote > :last-child {\n margin-bottom: 0;\n}\n\n.blockquote-footer {\n margin-top: -1rem;\n margin-bottom: 1rem;\n font-size: 0.875em;\n color: #6c757d;\n}\n.blockquote-footer::before {\n content: \"— \";\n}\n\n.img-fluid {\n max-width: 100%;\n height: auto;\n}\n\n.img-thumbnail {\n padding: 0.25rem;\n background-color: var(--bs-body-bg);\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n max-width: 100%;\n height: auto;\n}\n\n.figure {\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: 0.5rem;\n line-height: 1;\n}\n\n.figure-caption {\n font-size: 0.875em;\n color: var(--bs-secondary-color);\n}\n\n.container,\n.container-fluid,\n.container-xxl,\n.container-xl,\n.container-lg,\n.container-md,\n.container-sm {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container-sm, .container {\n max-width: 540px;\n }\n}\n@media (min-width: 768px) {\n .container-md, .container-sm, .container {\n max-width: 720px;\n }\n}\n@media (min-width: 992px) {\n .container-lg, .container-md, .container-sm, .container {\n max-width: 960px;\n }\n}\n@media (min-width: 1200px) {\n .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1140px;\n }\n}\n@media (min-width: 1400px) {\n .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1320px;\n }\n}\n:root {\n --bs-breakpoint-xs: 0;\n --bs-breakpoint-sm: 576px;\n --bs-breakpoint-md: 768px;\n --bs-breakpoint-lg: 992px;\n --bs-breakpoint-xl: 1200px;\n --bs-breakpoint-xxl: 1400px;\n}\n\n.row {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(-1 * var(--bs-gutter-y));\n margin-right: calc(-0.5 * var(--bs-gutter-x));\n margin-left: calc(-0.5 * var(--bs-gutter-x));\n}\n.row > * {\n flex-shrink: 0;\n width: 100%;\n max-width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-top: var(--bs-gutter-y);\n}\n\n.col {\n flex: 1 0 0%;\n}\n\n.row-cols-auto > * {\n flex: 0 0 auto;\n width: auto;\n}\n\n.row-cols-1 > * {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.row-cols-2 > * {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.row-cols-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.row-cols-4 > * {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.row-cols-5 > * {\n flex: 0 0 auto;\n width: 20%;\n}\n\n.row-cols-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n}\n\n.col-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n}\n\n.col-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-3 {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.col-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.col-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n}\n\n.col-6 {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.col-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n}\n\n.col-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n}\n\n.col-9 {\n flex: 0 0 auto;\n width: 75%;\n}\n\n.col-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n}\n\n.col-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n}\n\n.col-12 {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.offset-1 {\n margin-left: 8.33333333%;\n}\n\n.offset-2 {\n margin-left: 16.66666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.33333333%;\n}\n\n.offset-5 {\n margin-left: 41.66666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.33333333%;\n}\n\n.offset-8 {\n margin-left: 66.66666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.33333333%;\n}\n\n.offset-11 {\n margin-left: 91.66666667%;\n}\n\n.g-0,\n.gx-0 {\n --bs-gutter-x: 0;\n}\n\n.g-0,\n.gy-0 {\n --bs-gutter-y: 0;\n}\n\n.g-1,\n.gx-1 {\n --bs-gutter-x: 0.25rem;\n}\n\n.g-1,\n.gy-1 {\n --bs-gutter-y: 0.25rem;\n}\n\n.g-2,\n.gx-2 {\n --bs-gutter-x: 0.5rem;\n}\n\n.g-2,\n.gy-2 {\n --bs-gutter-y: 0.5rem;\n}\n\n.g-3,\n.gx-3 {\n --bs-gutter-x: 1rem;\n}\n\n.g-3,\n.gy-3 {\n --bs-gutter-y: 1rem;\n}\n\n.g-4,\n.gx-4 {\n --bs-gutter-x: 1.5rem;\n}\n\n.g-4,\n.gy-4 {\n --bs-gutter-y: 1.5rem;\n}\n\n.g-5,\n.gx-5 {\n --bs-gutter-x: 3rem;\n}\n\n.g-5,\n.gy-5 {\n --bs-gutter-y: 3rem;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex: 1 0 0%;\n }\n .row-cols-sm-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-sm-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-sm-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-sm-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-sm-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-sm-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-sm-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-sm-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-sm-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-sm-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-sm-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-sm-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-sm-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-sm-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-sm-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-sm-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-sm-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-sm-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-sm-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-sm-0 {\n margin-left: 0;\n }\n .offset-sm-1 {\n margin-left: 8.33333333%;\n }\n .offset-sm-2 {\n margin-left: 16.66666667%;\n }\n .offset-sm-3 {\n margin-left: 25%;\n }\n .offset-sm-4 {\n margin-left: 33.33333333%;\n }\n .offset-sm-5 {\n margin-left: 41.66666667%;\n }\n .offset-sm-6 {\n margin-left: 50%;\n }\n .offset-sm-7 {\n margin-left: 58.33333333%;\n }\n .offset-sm-8 {\n margin-left: 66.66666667%;\n }\n .offset-sm-9 {\n margin-left: 75%;\n }\n .offset-sm-10 {\n margin-left: 83.33333333%;\n }\n .offset-sm-11 {\n margin-left: 91.66666667%;\n }\n .g-sm-0,\n .gx-sm-0 {\n --bs-gutter-x: 0;\n }\n .g-sm-0,\n .gy-sm-0 {\n --bs-gutter-y: 0;\n }\n .g-sm-1,\n .gx-sm-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-sm-1,\n .gy-sm-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-sm-2,\n .gx-sm-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-sm-2,\n .gy-sm-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-sm-3,\n .gx-sm-3 {\n --bs-gutter-x: 1rem;\n }\n .g-sm-3,\n .gy-sm-3 {\n --bs-gutter-y: 1rem;\n }\n .g-sm-4,\n .gx-sm-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-sm-4,\n .gy-sm-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-sm-5,\n .gx-sm-5 {\n --bs-gutter-x: 3rem;\n }\n .g-sm-5,\n .gy-sm-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 768px) {\n .col-md {\n flex: 1 0 0%;\n }\n .row-cols-md-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-md-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-md-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-md-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-md-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-md-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-md-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-md-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-md-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-md-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-md-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-md-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-md-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-md-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-md-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-md-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-md-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-md-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-md-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-md-0 {\n margin-left: 0;\n }\n .offset-md-1 {\n margin-left: 8.33333333%;\n }\n .offset-md-2 {\n margin-left: 16.66666667%;\n }\n .offset-md-3 {\n margin-left: 25%;\n }\n .offset-md-4 {\n margin-left: 33.33333333%;\n }\n .offset-md-5 {\n margin-left: 41.66666667%;\n }\n .offset-md-6 {\n margin-left: 50%;\n }\n .offset-md-7 {\n margin-left: 58.33333333%;\n }\n .offset-md-8 {\n margin-left: 66.66666667%;\n }\n .offset-md-9 {\n margin-left: 75%;\n }\n .offset-md-10 {\n margin-left: 83.33333333%;\n }\n .offset-md-11 {\n margin-left: 91.66666667%;\n }\n .g-md-0,\n .gx-md-0 {\n --bs-gutter-x: 0;\n }\n .g-md-0,\n .gy-md-0 {\n --bs-gutter-y: 0;\n }\n .g-md-1,\n .gx-md-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-md-1,\n .gy-md-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-md-2,\n .gx-md-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-md-2,\n .gy-md-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-md-3,\n .gx-md-3 {\n --bs-gutter-x: 1rem;\n }\n .g-md-3,\n .gy-md-3 {\n --bs-gutter-y: 1rem;\n }\n .g-md-4,\n .gx-md-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-md-4,\n .gy-md-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-md-5,\n .gx-md-5 {\n --bs-gutter-x: 3rem;\n }\n .g-md-5,\n .gy-md-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 992px) {\n .col-lg {\n flex: 1 0 0%;\n }\n .row-cols-lg-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-lg-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-lg-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-lg-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-lg-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-lg-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-lg-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-lg-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-lg-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-lg-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-lg-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-lg-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-lg-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-lg-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-lg-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-lg-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-lg-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-lg-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-lg-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-lg-0 {\n margin-left: 0;\n }\n .offset-lg-1 {\n margin-left: 8.33333333%;\n }\n .offset-lg-2 {\n margin-left: 16.66666667%;\n }\n .offset-lg-3 {\n margin-left: 25%;\n }\n .offset-lg-4 {\n margin-left: 33.33333333%;\n }\n .offset-lg-5 {\n margin-left: 41.66666667%;\n }\n .offset-lg-6 {\n margin-left: 50%;\n }\n .offset-lg-7 {\n margin-left: 58.33333333%;\n }\n .offset-lg-8 {\n margin-left: 66.66666667%;\n }\n .offset-lg-9 {\n margin-left: 75%;\n }\n .offset-lg-10 {\n margin-left: 83.33333333%;\n }\n .offset-lg-11 {\n margin-left: 91.66666667%;\n }\n .g-lg-0,\n .gx-lg-0 {\n --bs-gutter-x: 0;\n }\n .g-lg-0,\n .gy-lg-0 {\n --bs-gutter-y: 0;\n }\n .g-lg-1,\n .gx-lg-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-lg-1,\n .gy-lg-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-lg-2,\n .gx-lg-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-lg-2,\n .gy-lg-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-lg-3,\n .gx-lg-3 {\n --bs-gutter-x: 1rem;\n }\n .g-lg-3,\n .gy-lg-3 {\n --bs-gutter-y: 1rem;\n }\n .g-lg-4,\n .gx-lg-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-lg-4,\n .gy-lg-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-lg-5,\n .gx-lg-5 {\n --bs-gutter-x: 3rem;\n }\n .g-lg-5,\n .gy-lg-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1200px) {\n .col-xl {\n flex: 1 0 0%;\n }\n .row-cols-xl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xl-0 {\n margin-left: 0;\n }\n .offset-xl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xl-3 {\n margin-left: 25%;\n }\n .offset-xl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xl-6 {\n margin-left: 50%;\n }\n .offset-xl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xl-9 {\n margin-left: 75%;\n }\n .offset-xl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xl-11 {\n margin-left: 91.66666667%;\n }\n .g-xl-0,\n .gx-xl-0 {\n --bs-gutter-x: 0;\n }\n .g-xl-0,\n .gy-xl-0 {\n --bs-gutter-y: 0;\n }\n .g-xl-1,\n .gx-xl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xl-1,\n .gy-xl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xl-2,\n .gx-xl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xl-2,\n .gy-xl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xl-3,\n .gx-xl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xl-3,\n .gy-xl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xl-4,\n .gx-xl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xl-4,\n .gy-xl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xl-5,\n .gx-xl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xl-5,\n .gy-xl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1400px) {\n .col-xxl {\n flex: 1 0 0%;\n }\n .row-cols-xxl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n .row-cols-xxl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n .row-cols-xxl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n .row-cols-xxl-3 > * {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .row-cols-xxl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n .row-cols-xxl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n .row-cols-xxl-6 > * {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n .col-xxl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n .col-xxl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n .col-xxl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n .col-xxl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n .col-xxl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n .col-xxl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n .col-xxl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n .col-xxl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n .col-xxl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n .col-xxl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n .col-xxl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n .col-xxl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n .offset-xxl-0 {\n margin-left: 0;\n }\n .offset-xxl-1 {\n margin-left: 8.33333333%;\n }\n .offset-xxl-2 {\n margin-left: 16.66666667%;\n }\n .offset-xxl-3 {\n margin-left: 25%;\n }\n .offset-xxl-4 {\n margin-left: 33.33333333%;\n }\n .offset-xxl-5 {\n margin-left: 41.66666667%;\n }\n .offset-xxl-6 {\n margin-left: 50%;\n }\n .offset-xxl-7 {\n margin-left: 58.33333333%;\n }\n .offset-xxl-8 {\n margin-left: 66.66666667%;\n }\n .offset-xxl-9 {\n margin-left: 75%;\n }\n .offset-xxl-10 {\n margin-left: 83.33333333%;\n }\n .offset-xxl-11 {\n margin-left: 91.66666667%;\n }\n .g-xxl-0,\n .gx-xxl-0 {\n --bs-gutter-x: 0;\n }\n .g-xxl-0,\n .gy-xxl-0 {\n --bs-gutter-y: 0;\n }\n .g-xxl-1,\n .gx-xxl-1 {\n --bs-gutter-x: 0.25rem;\n }\n .g-xxl-1,\n .gy-xxl-1 {\n --bs-gutter-y: 0.25rem;\n }\n .g-xxl-2,\n .gx-xxl-2 {\n --bs-gutter-x: 0.5rem;\n }\n .g-xxl-2,\n .gy-xxl-2 {\n --bs-gutter-y: 0.5rem;\n }\n .g-xxl-3,\n .gx-xxl-3 {\n --bs-gutter-x: 1rem;\n }\n .g-xxl-3,\n .gy-xxl-3 {\n --bs-gutter-y: 1rem;\n }\n .g-xxl-4,\n .gx-xxl-4 {\n --bs-gutter-x: 1.5rem;\n }\n .g-xxl-4,\n .gy-xxl-4 {\n --bs-gutter-y: 1.5rem;\n }\n .g-xxl-5,\n .gx-xxl-5 {\n --bs-gutter-x: 3rem;\n }\n .g-xxl-5,\n .gy-xxl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n.table {\n --bs-table-color-type: initial;\n --bs-table-bg-type: initial;\n --bs-table-color-state: initial;\n --bs-table-bg-state: initial;\n --bs-table-color: var(--bs-emphasis-color);\n --bs-table-bg: var(--bs-body-bg);\n --bs-table-border-color: var(--bs-border-color);\n --bs-table-accent-bg: transparent;\n --bs-table-striped-color: var(--bs-emphasis-color);\n --bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), 0.05);\n --bs-table-active-color: var(--bs-emphasis-color);\n --bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), 0.1);\n --bs-table-hover-color: var(--bs-emphasis-color);\n --bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.075);\n width: 100%;\n margin-bottom: 1rem;\n vertical-align: top;\n border-color: var(--bs-table-border-color);\n}\n.table > :not(caption) > * > * {\n padding: 0.5rem 0.5rem;\n color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));\n background-color: var(--bs-table-bg);\n border-bottom-width: var(--bs-border-width);\n box-shadow: inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)));\n}\n.table > tbody {\n vertical-align: inherit;\n}\n.table > thead {\n vertical-align: bottom;\n}\n\n.table-group-divider {\n border-top: calc(var(--bs-border-width) * 2) solid currentcolor;\n}\n\n.caption-top {\n caption-side: top;\n}\n\n.table-sm > :not(caption) > * > * {\n padding: 0.25rem 0.25rem;\n}\n\n.table-bordered > :not(caption) > * {\n border-width: var(--bs-border-width) 0;\n}\n.table-bordered > :not(caption) > * > * {\n border-width: 0 var(--bs-border-width);\n}\n\n.table-borderless > :not(caption) > * > * {\n border-bottom-width: 0;\n}\n.table-borderless > :not(:first-child) {\n border-top-width: 0;\n}\n\n.table-striped > tbody > tr:nth-of-type(odd) > * {\n --bs-table-color-type: var(--bs-table-striped-color);\n --bs-table-bg-type: var(--bs-table-striped-bg);\n}\n\n.table-striped-columns > :not(caption) > tr > :nth-child(even) {\n --bs-table-color-type: var(--bs-table-striped-color);\n --bs-table-bg-type: var(--bs-table-striped-bg);\n}\n\n.table-active {\n --bs-table-color-state: var(--bs-table-active-color);\n --bs-table-bg-state: var(--bs-table-active-bg);\n}\n\n.table-hover > tbody > tr:hover > * {\n --bs-table-color-state: var(--bs-table-hover-color);\n --bs-table-bg-state: var(--bs-table-hover-bg);\n}\n\n.table-primary {\n --bs-table-color: #000;\n --bs-table-bg: #cfe2ff;\n --bs-table-border-color: #a6b5cc;\n --bs-table-striped-bg: #c5d7f2;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #bacbe6;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #bfd1ec;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-secondary {\n --bs-table-color: #000;\n --bs-table-bg: #e2e3e5;\n --bs-table-border-color: #b5b6b7;\n --bs-table-striped-bg: #d7d8da;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #cbccce;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #d1d2d4;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-success {\n --bs-table-color: #000;\n --bs-table-bg: #d1e7dd;\n --bs-table-border-color: #a7b9b1;\n --bs-table-striped-bg: #c7dbd2;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #bcd0c7;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #c1d6cc;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-info {\n --bs-table-color: #000;\n --bs-table-bg: #cff4fc;\n --bs-table-border-color: #a6c3ca;\n --bs-table-striped-bg: #c5e8ef;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #badce3;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #bfe2e9;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-warning {\n --bs-table-color: #000;\n --bs-table-bg: #fff3cd;\n --bs-table-border-color: #ccc2a4;\n --bs-table-striped-bg: #f2e7c3;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #e6dbb9;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #ece1be;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-danger {\n --bs-table-color: #000;\n --bs-table-bg: #f8d7da;\n --bs-table-border-color: #c6acae;\n --bs-table-striped-bg: #eccccf;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #dfc2c4;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #e5c7ca;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-light {\n --bs-table-color: #000;\n --bs-table-bg: #f8f9fa;\n --bs-table-border-color: #c6c7c8;\n --bs-table-striped-bg: #ecedee;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #dfe0e1;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #e5e6e7;\n --bs-table-hover-color: #000;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-dark {\n --bs-table-color: #fff;\n --bs-table-bg: #212529;\n --bs-table-border-color: #4d5154;\n --bs-table-striped-bg: #2c3034;\n --bs-table-striped-color: #fff;\n --bs-table-active-bg: #373b3e;\n --bs-table-active-color: #fff;\n --bs-table-hover-bg: #323539;\n --bs-table-hover-color: #fff;\n color: var(--bs-table-color);\n border-color: var(--bs-table-border-color);\n}\n\n.table-responsive {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n@media (max-width: 575.98px) {\n .table-responsive-sm {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 767.98px) {\n .table-responsive-md {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 991.98px) {\n .table-responsive-lg {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 1199.98px) {\n .table-responsive-xl {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 1399.98px) {\n .table-responsive-xxl {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n.form-label {\n margin-bottom: 0.5rem;\n}\n\n.col-form-label {\n padding-top: calc(0.375rem + var(--bs-border-width));\n padding-bottom: calc(0.375rem + var(--bs-border-width));\n margin-bottom: 0;\n font-size: inherit;\n line-height: 1.5;\n}\n\n.col-form-label-lg {\n padding-top: calc(0.5rem + var(--bs-border-width));\n padding-bottom: calc(0.5rem + var(--bs-border-width));\n font-size: 1.25rem;\n}\n\n.col-form-label-sm {\n padding-top: calc(0.25rem + var(--bs-border-width));\n padding-bottom: calc(0.25rem + var(--bs-border-width));\n font-size: 0.875rem;\n}\n\n.form-text {\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: var(--bs-secondary-color);\n}\n\n.form-control {\n display: block;\n width: 100%;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: var(--bs-body-color);\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n background-color: var(--bs-body-bg);\n background-clip: padding-box;\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-control {\n transition: none;\n }\n}\n.form-control[type=file] {\n overflow: hidden;\n}\n.form-control[type=file]:not(:disabled):not([readonly]) {\n cursor: pointer;\n}\n.form-control:focus {\n color: var(--bs-body-color);\n background-color: var(--bs-body-bg);\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-control::-webkit-date-and-time-value {\n min-width: 85px;\n height: 1.5em;\n margin: 0;\n}\n.form-control::-webkit-datetime-edit {\n display: block;\n padding: 0;\n}\n.form-control::-moz-placeholder {\n color: var(--bs-secondary-color);\n opacity: 1;\n}\n.form-control::placeholder {\n color: var(--bs-secondary-color);\n opacity: 1;\n}\n.form-control:disabled {\n background-color: var(--bs-secondary-bg);\n opacity: 1;\n}\n.form-control::-webkit-file-upload-button {\n padding: 0.375rem 0.75rem;\n margin: -0.375rem -0.75rem;\n -webkit-margin-end: 0.75rem;\n margin-inline-end: 0.75rem;\n color: var(--bs-body-color);\n background-color: var(--bs-tertiary-bg);\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: var(--bs-border-width);\n border-radius: 0;\n -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n.form-control::file-selector-button {\n padding: 0.375rem 0.75rem;\n margin: -0.375rem -0.75rem;\n -webkit-margin-end: 0.75rem;\n margin-inline-end: 0.75rem;\n color: var(--bs-body-color);\n background-color: var(--bs-tertiary-bg);\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: var(--bs-border-width);\n border-radius: 0;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-control::-webkit-file-upload-button {\n -webkit-transition: none;\n transition: none;\n }\n .form-control::file-selector-button {\n transition: none;\n }\n}\n.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {\n background-color: var(--bs-secondary-bg);\n}\n.form-control:hover:not(:disabled):not([readonly])::file-selector-button {\n background-color: var(--bs-secondary-bg);\n}\n\n.form-control-plaintext {\n display: block;\n width: 100%;\n padding: 0.375rem 0;\n margin-bottom: 0;\n line-height: 1.5;\n color: var(--bs-body-color);\n background-color: transparent;\n border: solid transparent;\n border-width: var(--bs-border-width) 0;\n}\n.form-control-plaintext:focus {\n outline: 0;\n}\n.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {\n padding-right: 0;\n padding-left: 0;\n}\n\n.form-control-sm {\n min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: var(--bs-border-radius-sm);\n}\n.form-control-sm::-webkit-file-upload-button {\n padding: 0.25rem 0.5rem;\n margin: -0.25rem -0.5rem;\n -webkit-margin-end: 0.5rem;\n margin-inline-end: 0.5rem;\n}\n.form-control-sm::file-selector-button {\n padding: 0.25rem 0.5rem;\n margin: -0.25rem -0.5rem;\n -webkit-margin-end: 0.5rem;\n margin-inline-end: 0.5rem;\n}\n\n.form-control-lg {\n min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: var(--bs-border-radius-lg);\n}\n.form-control-lg::-webkit-file-upload-button {\n padding: 0.5rem 1rem;\n margin: -0.5rem -1rem;\n -webkit-margin-end: 1rem;\n margin-inline-end: 1rem;\n}\n.form-control-lg::file-selector-button {\n padding: 0.5rem 1rem;\n margin: -0.5rem -1rem;\n -webkit-margin-end: 1rem;\n margin-inline-end: 1rem;\n}\n\ntextarea.form-control {\n min-height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));\n}\ntextarea.form-control-sm {\n min-height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));\n}\ntextarea.form-control-lg {\n min-height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));\n}\n\n.form-control-color {\n width: 3rem;\n height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));\n padding: 0.375rem;\n}\n.form-control-color:not(:disabled):not([readonly]) {\n cursor: pointer;\n}\n.form-control-color::-moz-color-swatch {\n border: 0 !important;\n border-radius: var(--bs-border-radius);\n}\n.form-control-color::-webkit-color-swatch {\n border: 0 !important;\n border-radius: var(--bs-border-radius);\n}\n.form-control-color.form-control-sm {\n height: calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));\n}\n.form-control-color.form-control-lg {\n height: calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));\n}\n\n.form-select {\n --bs-form-select-bg-img: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e\");\n display: block;\n width: 100%;\n padding: 0.375rem 2.25rem 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: var(--bs-body-color);\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n background-color: var(--bs-body-bg);\n background-image: var(--bs-form-select-bg-img), var(--bs-form-select-bg-icon, none);\n background-repeat: no-repeat;\n background-position: right 0.75rem center;\n background-size: 16px 12px;\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-select {\n transition: none;\n }\n}\n.form-select:focus {\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-select[multiple], .form-select[size]:not([size=\"1\"]) {\n padding-right: 0.75rem;\n background-image: none;\n}\n.form-select:disabled {\n background-color: var(--bs-secondary-bg);\n}\n.form-select:-moz-focusring {\n color: transparent;\n text-shadow: 0 0 0 var(--bs-body-color);\n}\n\n.form-select-sm {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n padding-left: 0.5rem;\n font-size: 0.875rem;\n border-radius: var(--bs-border-radius-sm);\n}\n\n.form-select-lg {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n padding-left: 1rem;\n font-size: 1.25rem;\n border-radius: var(--bs-border-radius-lg);\n}\n\n[data-bs-theme=dark] .form-select {\n --bs-form-select-bg-img: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e\");\n}\n\n.form-check {\n display: block;\n min-height: 1.5rem;\n padding-left: 1.5em;\n margin-bottom: 0.125rem;\n}\n.form-check .form-check-input {\n float: left;\n margin-left: -1.5em;\n}\n\n.form-check-reverse {\n padding-right: 1.5em;\n padding-left: 0;\n text-align: right;\n}\n.form-check-reverse .form-check-input {\n float: right;\n margin-right: -1.5em;\n margin-left: 0;\n}\n\n.form-check-input {\n --bs-form-check-bg: var(--bs-body-bg);\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n margin-top: 0.25em;\n vertical-align: top;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n background-color: var(--bs-form-check-bg);\n background-image: var(--bs-form-check-bg-image);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border: var(--bs-border-width) solid var(--bs-border-color);\n -webkit-print-color-adjust: exact;\n color-adjust: exact;\n print-color-adjust: exact;\n}\n.form-check-input[type=checkbox] {\n border-radius: 0.25em;\n}\n.form-check-input[type=radio] {\n border-radius: 50%;\n}\n.form-check-input:active {\n filter: brightness(90%);\n}\n.form-check-input:focus {\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-check-input:checked {\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.form-check-input:checked[type=checkbox] {\n --bs-form-check-bg-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e\");\n}\n.form-check-input:checked[type=radio] {\n --bs-form-check-bg-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e\");\n}\n.form-check-input[type=checkbox]:indeterminate {\n background-color: #0d6efd;\n border-color: #0d6efd;\n --bs-form-check-bg-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e\");\n}\n.form-check-input:disabled {\n pointer-events: none;\n filter: none;\n opacity: 0.5;\n}\n.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label {\n cursor: default;\n opacity: 0.5;\n}\n\n.form-switch {\n padding-left: 2.5em;\n}\n.form-switch .form-check-input {\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e\");\n width: 2em;\n margin-left: -2.5em;\n background-image: var(--bs-form-switch-bg);\n background-position: left center;\n border-radius: 2em;\n transition: background-position 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-switch .form-check-input {\n transition: none;\n }\n}\n.form-switch .form-check-input:focus {\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e\");\n}\n.form-switch .form-check-input:checked {\n background-position: right center;\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e\");\n}\n.form-switch.form-check-reverse {\n padding-right: 2.5em;\n padding-left: 0;\n}\n.form-switch.form-check-reverse .form-check-input {\n margin-right: -2.5em;\n margin-left: 0;\n}\n\n.form-check-inline {\n display: inline-block;\n margin-right: 1rem;\n}\n\n.btn-check {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.btn-check[disabled] + .btn, .btn-check:disabled + .btn {\n pointer-events: none;\n filter: none;\n opacity: 0.65;\n}\n\n[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus) {\n --bs-form-switch-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e\");\n}\n\n.form-range {\n width: 100%;\n height: 1.5rem;\n padding: 0;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n background-color: transparent;\n}\n.form-range:focus {\n outline: 0;\n}\n.form-range:focus::-webkit-slider-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-range:focus::-moz-range-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-range::-moz-focus-outer {\n border: 0;\n}\n.form-range::-webkit-slider-thumb {\n width: 1rem;\n height: 1rem;\n margin-top: -0.25rem;\n -webkit-appearance: none;\n appearance: none;\n background-color: #0d6efd;\n border: 0;\n border-radius: 1rem;\n -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-range::-webkit-slider-thumb {\n -webkit-transition: none;\n transition: none;\n }\n}\n.form-range::-webkit-slider-thumb:active {\n background-color: #b6d4fe;\n}\n.form-range::-webkit-slider-runnable-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: var(--bs-secondary-bg);\n border-color: transparent;\n border-radius: 1rem;\n}\n.form-range::-moz-range-thumb {\n width: 1rem;\n height: 1rem;\n -moz-appearance: none;\n appearance: none;\n background-color: #0d6efd;\n border: 0;\n border-radius: 1rem;\n -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-range::-moz-range-thumb {\n -moz-transition: none;\n transition: none;\n }\n}\n.form-range::-moz-range-thumb:active {\n background-color: #b6d4fe;\n}\n.form-range::-moz-range-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: var(--bs-secondary-bg);\n border-color: transparent;\n border-radius: 1rem;\n}\n.form-range:disabled {\n pointer-events: none;\n}\n.form-range:disabled::-webkit-slider-thumb {\n background-color: var(--bs-secondary-color);\n}\n.form-range:disabled::-moz-range-thumb {\n background-color: var(--bs-secondary-color);\n}\n\n.form-floating {\n position: relative;\n}\n.form-floating > .form-control,\n.form-floating > .form-control-plaintext,\n.form-floating > .form-select {\n height: calc(3.5rem + calc(var(--bs-border-width) * 2));\n min-height: calc(3.5rem + calc(var(--bs-border-width) * 2));\n line-height: 1.25;\n}\n.form-floating > label {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n height: 100%;\n padding: 1rem 0.75rem;\n overflow: hidden;\n text-align: start;\n text-overflow: ellipsis;\n white-space: nowrap;\n pointer-events: none;\n border: var(--bs-border-width) solid transparent;\n transform-origin: 0 0;\n transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-floating > label {\n transition: none;\n }\n}\n.form-floating > .form-control,\n.form-floating > .form-control-plaintext {\n padding: 1rem 0.75rem;\n}\n.form-floating > .form-control::-moz-placeholder, .form-floating > .form-control-plaintext::-moz-placeholder {\n color: transparent;\n}\n.form-floating > .form-control::placeholder,\n.form-floating > .form-control-plaintext::placeholder {\n color: transparent;\n}\n.form-floating > .form-control:not(:-moz-placeholder-shown), .form-floating > .form-control-plaintext:not(:-moz-placeholder-shown) {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown),\n.form-floating > .form-control-plaintext:focus,\n.form-floating > .form-control-plaintext:not(:placeholder-shown) {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:-webkit-autofill,\n.form-floating > .form-control-plaintext:-webkit-autofill {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-select {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label {\n color: rgba(var(--bs-body-color-rgb), 0.65);\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n.form-floating > .form-control:focus ~ label,\n.form-floating > .form-control:not(:placeholder-shown) ~ label,\n.form-floating > .form-control-plaintext ~ label,\n.form-floating > .form-select ~ label {\n color: rgba(var(--bs-body-color-rgb), 0.65);\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label::after {\n position: absolute;\n inset: 1rem 0.375rem;\n z-index: -1;\n height: 1.5em;\n content: \"\";\n background-color: var(--bs-body-bg);\n border-radius: var(--bs-border-radius);\n}\n.form-floating > .form-control:focus ~ label::after,\n.form-floating > .form-control:not(:placeholder-shown) ~ label::after,\n.form-floating > .form-control-plaintext ~ label::after,\n.form-floating > .form-select ~ label::after {\n position: absolute;\n inset: 1rem 0.375rem;\n z-index: -1;\n height: 1.5em;\n content: \"\";\n background-color: var(--bs-body-bg);\n border-radius: var(--bs-border-radius);\n}\n.form-floating > .form-control:-webkit-autofill ~ label {\n color: rgba(var(--bs-body-color-rgb), 0.65);\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n.form-floating > .form-control-plaintext ~ label {\n border-width: var(--bs-border-width) 0;\n}\n.form-floating > :disabled ~ label,\n.form-floating > .form-control:disabled ~ label {\n color: #6c757d;\n}\n.form-floating > :disabled ~ label::after,\n.form-floating > .form-control:disabled ~ label::after {\n background-color: var(--bs-secondary-bg);\n}\n\n.input-group {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n width: 100%;\n}\n.input-group > .form-control,\n.input-group > .form-select,\n.input-group > .form-floating {\n position: relative;\n flex: 1 1 auto;\n width: 1%;\n min-width: 0;\n}\n.input-group > .form-control:focus,\n.input-group > .form-select:focus,\n.input-group > .form-floating:focus-within {\n z-index: 5;\n}\n.input-group .btn {\n position: relative;\n z-index: 2;\n}\n.input-group .btn:focus {\n z-index: 5;\n}\n\n.input-group-text {\n display: flex;\n align-items: center;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: var(--bs-body-color);\n text-align: center;\n white-space: nowrap;\n background-color: var(--bs-tertiary-bg);\n border: var(--bs-border-width) solid var(--bs-border-color);\n border-radius: var(--bs-border-radius);\n}\n\n.input-group-lg > .form-control,\n.input-group-lg > .form-select,\n.input-group-lg > .input-group-text,\n.input-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: var(--bs-border-radius-lg);\n}\n\n.input-group-sm > .form-control,\n.input-group-sm > .form-select,\n.input-group-sm > .input-group-text,\n.input-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: var(--bs-border-radius-sm);\n}\n\n.input-group-lg > .form-select,\n.input-group-sm > .form-select {\n padding-right: 3rem;\n}\n\n.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\n.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3),\n.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control,\n.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\n.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4),\n.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control,\n.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {\n margin-left: calc(var(--bs-border-width) * -1);\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.input-group > .form-floating:not(:first-child) > .form-control,\n.input-group > .form-floating:not(:first-child) > .form-select {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.valid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: var(--bs-form-valid-color);\n}\n\n.valid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: 0.1rem;\n font-size: 0.875rem;\n color: #fff;\n background-color: var(--bs-success);\n border-radius: var(--bs-border-radius);\n}\n\n.was-validated :valid ~ .valid-feedback,\n.was-validated :valid ~ .valid-tooltip,\n.is-valid ~ .valid-feedback,\n.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid {\n border-color: var(--bs-form-valid-border-color);\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: right calc(0.375em + 0.1875rem) center;\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus {\n border-color: var(--bs-form-valid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);\n}\n\n.was-validated textarea.form-control:valid, textarea.form-control.is-valid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .form-select:valid, .form-select.is-valid {\n border-color: var(--bs-form-valid-border-color);\n}\n.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size=\"1\"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size=\"1\"] {\n --bs-form-select-bg-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n padding-right: 4.125rem;\n background-position: right 0.75rem center, center right 2.25rem;\n background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-select:valid:focus, .form-select.is-valid:focus {\n border-color: var(--bs-form-valid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);\n}\n\n.was-validated .form-control-color:valid, .form-control-color.is-valid {\n width: calc(3rem + calc(1.5em + 0.75rem));\n}\n\n.was-validated .form-check-input:valid, .form-check-input.is-valid {\n border-color: var(--bs-form-valid-border-color);\n}\n.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {\n background-color: var(--bs-form-valid-color);\n}\n.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus {\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25);\n}\n.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {\n color: var(--bs-form-valid-color);\n}\n\n.form-check-inline .form-check-input ~ .valid-feedback {\n margin-left: 0.5em;\n}\n\n.was-validated .input-group > .form-control:not(:focus):valid, .input-group > .form-control:not(:focus).is-valid,\n.was-validated .input-group > .form-select:not(:focus):valid,\n.input-group > .form-select:not(:focus).is-valid,\n.was-validated .input-group > .form-floating:not(:focus-within):valid,\n.input-group > .form-floating:not(:focus-within).is-valid {\n z-index: 3;\n}\n\n.invalid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: var(--bs-form-invalid-color);\n}\n\n.invalid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: 0.1rem;\n font-size: 0.875rem;\n color: #fff;\n background-color: var(--bs-danger);\n border-radius: var(--bs-border-radius);\n}\n\n.was-validated :invalid ~ .invalid-feedback,\n.was-validated :invalid ~ .invalid-tooltip,\n.is-invalid ~ .invalid-feedback,\n.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid {\n border-color: var(--bs-form-invalid-border-color);\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: right calc(0.375em + 0.1875rem) center;\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {\n border-color: var(--bs-form-invalid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);\n}\n\n.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .form-select:invalid, .form-select.is-invalid {\n border-color: var(--bs-form-invalid-border-color);\n}\n.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size=\"1\"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size=\"1\"] {\n --bs-form-select-bg-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\");\n padding-right: 4.125rem;\n background-position: right 0.75rem center, center right 2.25rem;\n background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus {\n border-color: var(--bs-form-invalid-border-color);\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);\n}\n\n.was-validated .form-control-color:invalid, .form-control-color.is-invalid {\n width: calc(3rem + calc(1.5em + 0.75rem));\n}\n\n.was-validated .form-check-input:invalid, .form-check-input.is-invalid {\n border-color: var(--bs-form-invalid-border-color);\n}\n.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked {\n background-color: var(--bs-form-invalid-color);\n}\n.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus {\n box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);\n}\n.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {\n color: var(--bs-form-invalid-color);\n}\n\n.form-check-inline .form-check-input ~ .invalid-feedback {\n margin-left: 0.5em;\n}\n\n.was-validated .input-group > .form-control:not(:focus):invalid, .input-group > .form-control:not(:focus).is-invalid,\n.was-validated .input-group > .form-select:not(:focus):invalid,\n.input-group > .form-select:not(:focus).is-invalid,\n.was-validated .input-group > .form-floating:not(:focus-within):invalid,\n.input-group > .form-floating:not(:focus-within).is-invalid {\n z-index: 4;\n}\n\n.btn {\n --bs-btn-padding-x: 0.75rem;\n --bs-btn-padding-y: 0.375rem;\n --bs-btn-font-family: ;\n --bs-btn-font-size: 1rem;\n --bs-btn-font-weight: 400;\n --bs-btn-line-height: 1.5;\n --bs-btn-color: var(--bs-body-color);\n --bs-btn-bg: transparent;\n --bs-btn-border-width: var(--bs-border-width);\n --bs-btn-border-color: transparent;\n --bs-btn-border-radius: var(--bs-border-radius);\n --bs-btn-hover-border-color: transparent;\n --bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n --bs-btn-disabled-opacity: 0.65;\n --bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);\n display: inline-block;\n padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x);\n font-family: var(--bs-btn-font-family);\n font-size: var(--bs-btn-font-size);\n font-weight: var(--bs-btn-font-weight);\n line-height: var(--bs-btn-line-height);\n color: var(--bs-btn-color);\n text-align: center;\n text-decoration: none;\n vertical-align: middle;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n border: var(--bs-btn-border-width) solid var(--bs-btn-border-color);\n border-radius: var(--bs-btn-border-radius);\n background-color: var(--bs-btn-bg);\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .btn {\n transition: none;\n }\n}\n.btn:hover {\n color: var(--bs-btn-hover-color);\n background-color: var(--bs-btn-hover-bg);\n border-color: var(--bs-btn-hover-border-color);\n}\n.btn-check + .btn:hover {\n color: var(--bs-btn-color);\n background-color: var(--bs-btn-bg);\n border-color: var(--bs-btn-border-color);\n}\n.btn:focus-visible {\n color: var(--bs-btn-hover-color);\n background-color: var(--bs-btn-hover-bg);\n border-color: var(--bs-btn-hover-border-color);\n outline: 0;\n box-shadow: var(--bs-btn-focus-box-shadow);\n}\n.btn-check:focus-visible + .btn {\n border-color: var(--bs-btn-hover-border-color);\n outline: 0;\n box-shadow: var(--bs-btn-focus-box-shadow);\n}\n.btn-check:checked + .btn, :not(.btn-check) + .btn:active, .btn:first-child:active, .btn.active, .btn.show {\n color: var(--bs-btn-active-color);\n background-color: var(--bs-btn-active-bg);\n border-color: var(--bs-btn-active-border-color);\n}\n.btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, .btn.active:focus-visible, .btn.show:focus-visible {\n box-shadow: var(--bs-btn-focus-box-shadow);\n}\n.btn:disabled, .btn.disabled, fieldset:disabled .btn {\n color: var(--bs-btn-disabled-color);\n pointer-events: none;\n background-color: var(--bs-btn-disabled-bg);\n border-color: var(--bs-btn-disabled-border-color);\n opacity: var(--bs-btn-disabled-opacity);\n}\n\n.btn-primary {\n --bs-btn-color: #fff;\n --bs-btn-bg: #0d6efd;\n --bs-btn-border-color: #0d6efd;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #0b5ed7;\n --bs-btn-hover-border-color: #0a58ca;\n --bs-btn-focus-shadow-rgb: 49, 132, 253;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #0a58ca;\n --bs-btn-active-border-color: #0a53be;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #0d6efd;\n --bs-btn-disabled-border-color: #0d6efd;\n}\n\n.btn-secondary {\n --bs-btn-color: #fff;\n --bs-btn-bg: #6c757d;\n --bs-btn-border-color: #6c757d;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #5c636a;\n --bs-btn-hover-border-color: #565e64;\n --bs-btn-focus-shadow-rgb: 130, 138, 145;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #565e64;\n --bs-btn-active-border-color: #51585e;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #6c757d;\n --bs-btn-disabled-border-color: #6c757d;\n}\n\n.btn-success {\n --bs-btn-color: #fff;\n --bs-btn-bg: #198754;\n --bs-btn-border-color: #198754;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #157347;\n --bs-btn-hover-border-color: #146c43;\n --bs-btn-focus-shadow-rgb: 60, 153, 110;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #146c43;\n --bs-btn-active-border-color: #13653f;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #198754;\n --bs-btn-disabled-border-color: #198754;\n}\n\n.btn-info {\n --bs-btn-color: #000;\n --bs-btn-bg: #0dcaf0;\n --bs-btn-border-color: #0dcaf0;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #31d2f2;\n --bs-btn-hover-border-color: #25cff2;\n --bs-btn-focus-shadow-rgb: 11, 172, 204;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #3dd5f3;\n --bs-btn-active-border-color: #25cff2;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #000;\n --bs-btn-disabled-bg: #0dcaf0;\n --bs-btn-disabled-border-color: #0dcaf0;\n}\n\n.btn-warning {\n --bs-btn-color: #000;\n --bs-btn-bg: #ffc107;\n --bs-btn-border-color: #ffc107;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #ffca2c;\n --bs-btn-hover-border-color: #ffc720;\n --bs-btn-focus-shadow-rgb: 217, 164, 6;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #ffcd39;\n --bs-btn-active-border-color: #ffc720;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #000;\n --bs-btn-disabled-bg: #ffc107;\n --bs-btn-disabled-border-color: #ffc107;\n}\n\n.btn-danger {\n --bs-btn-color: #fff;\n --bs-btn-bg: #dc3545;\n --bs-btn-border-color: #dc3545;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #bb2d3b;\n --bs-btn-hover-border-color: #b02a37;\n --bs-btn-focus-shadow-rgb: 225, 83, 97;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #b02a37;\n --bs-btn-active-border-color: #a52834;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #dc3545;\n --bs-btn-disabled-border-color: #dc3545;\n}\n\n.btn-light {\n --bs-btn-color: #000;\n --bs-btn-bg: #f8f9fa;\n --bs-btn-border-color: #f8f9fa;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #d3d4d5;\n --bs-btn-hover-border-color: #c6c7c8;\n --bs-btn-focus-shadow-rgb: 211, 212, 213;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #c6c7c8;\n --bs-btn-active-border-color: #babbbc;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #000;\n --bs-btn-disabled-bg: #f8f9fa;\n --bs-btn-disabled-border-color: #f8f9fa;\n}\n\n.btn-dark {\n --bs-btn-color: #fff;\n --bs-btn-bg: #212529;\n --bs-btn-border-color: #212529;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #424649;\n --bs-btn-hover-border-color: #373b3e;\n --bs-btn-focus-shadow-rgb: 66, 70, 73;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #4d5154;\n --bs-btn-active-border-color: #373b3e;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #212529;\n --bs-btn-disabled-border-color: #212529;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #0d6efd;\n --bs-btn-border-color: #0d6efd;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #0d6efd;\n --bs-btn-hover-border-color: #0d6efd;\n --bs-btn-focus-shadow-rgb: 13, 110, 253;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #0d6efd;\n --bs-btn-active-border-color: #0d6efd;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #0d6efd;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #0d6efd;\n --bs-gradient: none;\n}\n\n.btn-outline-secondary {\n --bs-btn-color: #6c757d;\n --bs-btn-border-color: #6c757d;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #6c757d;\n --bs-btn-hover-border-color: #6c757d;\n --bs-btn-focus-shadow-rgb: 108, 117, 125;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #6c757d;\n --bs-btn-active-border-color: #6c757d;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #6c757d;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #6c757d;\n --bs-gradient: none;\n}\n\n.btn-outline-success {\n --bs-btn-color: #198754;\n --bs-btn-border-color: #198754;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #198754;\n --bs-btn-hover-border-color: #198754;\n --bs-btn-focus-shadow-rgb: 25, 135, 84;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #198754;\n --bs-btn-active-border-color: #198754;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #198754;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #198754;\n --bs-gradient: none;\n}\n\n.btn-outline-info {\n --bs-btn-color: #0dcaf0;\n --bs-btn-border-color: #0dcaf0;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #0dcaf0;\n --bs-btn-hover-border-color: #0dcaf0;\n --bs-btn-focus-shadow-rgb: 13, 202, 240;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #0dcaf0;\n --bs-btn-active-border-color: #0dcaf0;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #0dcaf0;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #0dcaf0;\n --bs-gradient: none;\n}\n\n.btn-outline-warning {\n --bs-btn-color: #ffc107;\n --bs-btn-border-color: #ffc107;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #ffc107;\n --bs-btn-hover-border-color: #ffc107;\n --bs-btn-focus-shadow-rgb: 255, 193, 7;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #ffc107;\n --bs-btn-active-border-color: #ffc107;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #ffc107;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #ffc107;\n --bs-gradient: none;\n}\n\n.btn-outline-danger {\n --bs-btn-color: #dc3545;\n --bs-btn-border-color: #dc3545;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #dc3545;\n --bs-btn-hover-border-color: #dc3545;\n --bs-btn-focus-shadow-rgb: 220, 53, 69;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #dc3545;\n --bs-btn-active-border-color: #dc3545;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #dc3545;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #dc3545;\n --bs-gradient: none;\n}\n\n.btn-outline-light {\n --bs-btn-color: #f8f9fa;\n --bs-btn-border-color: #f8f9fa;\n --bs-btn-hover-color: #000;\n --bs-btn-hover-bg: #f8f9fa;\n --bs-btn-hover-border-color: #f8f9fa;\n --bs-btn-focus-shadow-rgb: 248, 249, 250;\n --bs-btn-active-color: #000;\n --bs-btn-active-bg: #f8f9fa;\n --bs-btn-active-border-color: #f8f9fa;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #f8f9fa;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #f8f9fa;\n --bs-gradient: none;\n}\n\n.btn-outline-dark {\n --bs-btn-color: #212529;\n --bs-btn-border-color: #212529;\n --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #212529;\n --bs-btn-hover-border-color: #212529;\n --bs-btn-focus-shadow-rgb: 33, 37, 41;\n --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #212529;\n --bs-btn-active-border-color: #212529;\n --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #212529;\n --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #212529;\n --bs-gradient: none;\n}\n\n.btn-link {\n --bs-btn-font-weight: 400;\n --bs-btn-color: var(--bs-link-color);\n --bs-btn-bg: transparent;\n --bs-btn-border-color: transparent;\n --bs-btn-hover-color: var(--bs-link-hover-color);\n --bs-btn-hover-border-color: transparent;\n --bs-btn-active-color: var(--bs-link-hover-color);\n --bs-btn-active-border-color: transparent;\n --bs-btn-disabled-color: #6c757d;\n --bs-btn-disabled-border-color: transparent;\n --bs-btn-box-shadow: 0 0 0 #000;\n --bs-btn-focus-shadow-rgb: 49, 132, 253;\n text-decoration: underline;\n}\n.btn-link:focus-visible {\n color: var(--bs-btn-color);\n}\n.btn-link:hover {\n color: var(--bs-btn-hover-color);\n}\n\n.btn-lg, .btn-group-lg > .btn {\n --bs-btn-padding-y: 0.5rem;\n --bs-btn-padding-x: 1rem;\n --bs-btn-font-size: 1.25rem;\n --bs-btn-border-radius: var(--bs-border-radius-lg);\n}\n\n.btn-sm, .btn-group-sm > .btn {\n --bs-btn-padding-y: 0.25rem;\n --bs-btn-padding-x: 0.5rem;\n --bs-btn-font-size: 0.875rem;\n --bs-btn-border-radius: var(--bs-border-radius-sm);\n}\n\n.fade {\n transition: opacity 0.15s linear;\n}\n@media (prefers-reduced-motion: reduce) {\n .fade {\n transition: none;\n }\n}\n.fade:not(.show) {\n opacity: 0;\n}\n\n.collapse:not(.show) {\n display: none;\n}\n\n.collapsing {\n height: 0;\n overflow: hidden;\n transition: height 0.35s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .collapsing {\n transition: none;\n }\n}\n.collapsing.collapse-horizontal {\n width: 0;\n height: auto;\n transition: width 0.35s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .collapsing.collapse-horizontal {\n transition: none;\n }\n}\n\n.dropup,\n.dropend,\n.dropdown,\n.dropstart,\n.dropup-center,\n.dropdown-center {\n position: relative;\n}\n\n.dropdown-toggle {\n white-space: nowrap;\n}\n.dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid;\n border-right: 0.3em solid transparent;\n border-bottom: 0;\n border-left: 0.3em solid transparent;\n}\n.dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropdown-menu {\n --bs-dropdown-zindex: 1000;\n --bs-dropdown-min-width: 10rem;\n --bs-dropdown-padding-x: 0;\n --bs-dropdown-padding-y: 0.5rem;\n --bs-dropdown-spacer: 0.125rem;\n --bs-dropdown-font-size: 1rem;\n --bs-dropdown-color: var(--bs-body-color);\n --bs-dropdown-bg: var(--bs-body-bg);\n --bs-dropdown-border-color: var(--bs-border-color-translucent);\n --bs-dropdown-border-radius: var(--bs-border-radius);\n --bs-dropdown-border-width: var(--bs-border-width);\n --bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));\n --bs-dropdown-divider-bg: var(--bs-border-color-translucent);\n --bs-dropdown-divider-margin-y: 0.5rem;\n --bs-dropdown-box-shadow: var(--bs-box-shadow);\n --bs-dropdown-link-color: var(--bs-body-color);\n --bs-dropdown-link-hover-color: var(--bs-body-color);\n --bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);\n --bs-dropdown-link-active-color: #fff;\n --bs-dropdown-link-active-bg: #0d6efd;\n --bs-dropdown-link-disabled-color: var(--bs-tertiary-color);\n --bs-dropdown-item-padding-x: 1rem;\n --bs-dropdown-item-padding-y: 0.25rem;\n --bs-dropdown-header-color: #6c757d;\n --bs-dropdown-header-padding-x: 1rem;\n --bs-dropdown-header-padding-y: 0.5rem;\n position: absolute;\n z-index: var(--bs-dropdown-zindex);\n display: none;\n min-width: var(--bs-dropdown-min-width);\n padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);\n margin: 0;\n font-size: var(--bs-dropdown-font-size);\n color: var(--bs-dropdown-color);\n text-align: left;\n list-style: none;\n background-color: var(--bs-dropdown-bg);\n background-clip: padding-box;\n border: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);\n border-radius: var(--bs-dropdown-border-radius);\n}\n.dropdown-menu[data-bs-popper] {\n top: 100%;\n left: 0;\n margin-top: var(--bs-dropdown-spacer);\n}\n\n.dropdown-menu-start {\n --bs-position: start;\n}\n.dropdown-menu-start[data-bs-popper] {\n right: auto;\n left: 0;\n}\n\n.dropdown-menu-end {\n --bs-position: end;\n}\n.dropdown-menu-end[data-bs-popper] {\n right: 0;\n left: auto;\n}\n\n@media (min-width: 576px) {\n .dropdown-menu-sm-start {\n --bs-position: start;\n }\n .dropdown-menu-sm-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-sm-end {\n --bs-position: end;\n }\n .dropdown-menu-sm-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 768px) {\n .dropdown-menu-md-start {\n --bs-position: start;\n }\n .dropdown-menu-md-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-md-end {\n --bs-position: end;\n }\n .dropdown-menu-md-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 992px) {\n .dropdown-menu-lg-start {\n --bs-position: start;\n }\n .dropdown-menu-lg-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-lg-end {\n --bs-position: end;\n }\n .dropdown-menu-lg-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 1200px) {\n .dropdown-menu-xl-start {\n --bs-position: start;\n }\n .dropdown-menu-xl-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-xl-end {\n --bs-position: end;\n }\n .dropdown-menu-xl-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 1400px) {\n .dropdown-menu-xxl-start {\n --bs-position: start;\n }\n .dropdown-menu-xxl-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n .dropdown-menu-xxl-end {\n --bs-position: end;\n }\n .dropdown-menu-xxl-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n.dropup .dropdown-menu[data-bs-popper] {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: var(--bs-dropdown-spacer);\n}\n.dropup .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0;\n border-right: 0.3em solid transparent;\n border-bottom: 0.3em solid;\n border-left: 0.3em solid transparent;\n}\n.dropup .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropend .dropdown-menu[data-bs-popper] {\n top: 0;\n right: auto;\n left: 100%;\n margin-top: 0;\n margin-left: var(--bs-dropdown-spacer);\n}\n.dropend .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0;\n border-bottom: 0.3em solid transparent;\n border-left: 0.3em solid;\n}\n.dropend .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n.dropend .dropdown-toggle::after {\n vertical-align: 0;\n}\n\n.dropstart .dropdown-menu[data-bs-popper] {\n top: 0;\n right: 100%;\n left: auto;\n margin-top: 0;\n margin-right: var(--bs-dropdown-spacer);\n}\n.dropstart .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n}\n.dropstart .dropdown-toggle::after {\n display: none;\n}\n.dropstart .dropdown-toggle::before {\n display: inline-block;\n margin-right: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0.3em solid;\n border-bottom: 0.3em solid transparent;\n}\n.dropstart .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n.dropstart .dropdown-toggle::before {\n vertical-align: 0;\n}\n\n.dropdown-divider {\n height: 0;\n margin: var(--bs-dropdown-divider-margin-y) 0;\n overflow: hidden;\n border-top: 1px solid var(--bs-dropdown-divider-bg);\n opacity: 1;\n}\n\n.dropdown-item {\n display: block;\n width: 100%;\n padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);\n clear: both;\n font-weight: 400;\n color: var(--bs-dropdown-link-color);\n text-align: inherit;\n text-decoration: none;\n white-space: nowrap;\n background-color: transparent;\n border: 0;\n border-radius: var(--bs-dropdown-item-border-radius, 0);\n}\n.dropdown-item:hover, .dropdown-item:focus {\n color: var(--bs-dropdown-link-hover-color);\n background-color: var(--bs-dropdown-link-hover-bg);\n}\n.dropdown-item.active, .dropdown-item:active {\n color: var(--bs-dropdown-link-active-color);\n text-decoration: none;\n background-color: var(--bs-dropdown-link-active-bg);\n}\n.dropdown-item.disabled, .dropdown-item:disabled {\n color: var(--bs-dropdown-link-disabled-color);\n pointer-events: none;\n background-color: transparent;\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n.dropdown-header {\n display: block;\n padding: var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);\n margin-bottom: 0;\n font-size: 0.875rem;\n color: var(--bs-dropdown-header-color);\n white-space: nowrap;\n}\n\n.dropdown-item-text {\n display: block;\n padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);\n color: var(--bs-dropdown-link-color);\n}\n\n.dropdown-menu-dark {\n --bs-dropdown-color: #dee2e6;\n --bs-dropdown-bg: #343a40;\n --bs-dropdown-border-color: var(--bs-border-color-translucent);\n --bs-dropdown-box-shadow: ;\n --bs-dropdown-link-color: #dee2e6;\n --bs-dropdown-link-hover-color: #fff;\n --bs-dropdown-divider-bg: var(--bs-border-color-translucent);\n --bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);\n --bs-dropdown-link-active-color: #fff;\n --bs-dropdown-link-active-bg: #0d6efd;\n --bs-dropdown-link-disabled-color: #adb5bd;\n --bs-dropdown-header-color: #adb5bd;\n}\n\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-flex;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n flex: 1 1 auto;\n}\n.btn-group > .btn-check:checked + .btn,\n.btn-group > .btn-check:focus + .btn,\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn-check:checked + .btn,\n.btn-group-vertical > .btn-check:focus + .btn,\n.btn-group-vertical > .btn:hover,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n z-index: 1;\n}\n\n.btn-toolbar {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-start;\n}\n.btn-toolbar .input-group {\n width: auto;\n}\n\n.btn-group {\n border-radius: var(--bs-border-radius);\n}\n.btn-group > :not(.btn-check:first-child) + .btn,\n.btn-group > .btn-group:not(:first-child) {\n margin-left: calc(var(--bs-border-width) * -1);\n}\n.btn-group > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group > .btn.dropdown-toggle-split:first-child,\n.btn-group > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:nth-child(n+3),\n.btn-group > :not(.btn-check) + .btn,\n.btn-group > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.dropdown-toggle-split {\n padding-right: 0.5625rem;\n padding-left: 0.5625rem;\n}\n.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after {\n margin-left: 0;\n}\n.dropstart .dropdown-toggle-split::before {\n margin-right: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n padding-right: 0.375rem;\n padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n padding-right: 0.75rem;\n padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group {\n width: 100%;\n}\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) {\n margin-top: calc(var(--bs-border-width) * -1);\n}\n.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group-vertical > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn ~ .btn,\n.btn-group-vertical > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav {\n --bs-nav-link-padding-x: 1rem;\n --bs-nav-link-padding-y: 0.5rem;\n --bs-nav-link-font-weight: ;\n --bs-nav-link-color: var(--bs-link-color);\n --bs-nav-link-hover-color: var(--bs-link-hover-color);\n --bs-nav-link-disabled-color: var(--bs-secondary-color);\n display: flex;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);\n font-size: var(--bs-nav-link-font-size);\n font-weight: var(--bs-nav-link-font-weight);\n color: var(--bs-nav-link-color);\n text-decoration: none;\n background: none;\n border: 0;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .nav-link {\n transition: none;\n }\n}\n.nav-link:hover, .nav-link:focus {\n color: var(--bs-nav-link-hover-color);\n}\n.nav-link:focus-visible {\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.nav-link.disabled, .nav-link:disabled {\n color: var(--bs-nav-link-disabled-color);\n pointer-events: none;\n cursor: default;\n}\n\n.nav-tabs {\n --bs-nav-tabs-border-width: var(--bs-border-width);\n --bs-nav-tabs-border-color: var(--bs-border-color);\n --bs-nav-tabs-border-radius: var(--bs-border-radius);\n --bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);\n --bs-nav-tabs-link-active-color: var(--bs-emphasis-color);\n --bs-nav-tabs-link-active-bg: var(--bs-body-bg);\n --bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);\n border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color);\n}\n.nav-tabs .nav-link {\n margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width));\n border: var(--bs-nav-tabs-border-width) solid transparent;\n border-top-left-radius: var(--bs-nav-tabs-border-radius);\n border-top-right-radius: var(--bs-nav-tabs-border-radius);\n}\n.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {\n isolation: isolate;\n border-color: var(--bs-nav-tabs-link-hover-border-color);\n}\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n color: var(--bs-nav-tabs-link-active-color);\n background-color: var(--bs-nav-tabs-link-active-bg);\n border-color: var(--bs-nav-tabs-link-active-border-color);\n}\n.nav-tabs .dropdown-menu {\n margin-top: calc(-1 * var(--bs-nav-tabs-border-width));\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav-pills {\n --bs-nav-pills-border-radius: var(--bs-border-radius);\n --bs-nav-pills-link-active-color: #fff;\n --bs-nav-pills-link-active-bg: #0d6efd;\n}\n.nav-pills .nav-link {\n border-radius: var(--bs-nav-pills-border-radius);\n}\n.nav-pills .nav-link.active,\n.nav-pills .show > .nav-link {\n color: var(--bs-nav-pills-link-active-color);\n background-color: var(--bs-nav-pills-link-active-bg);\n}\n\n.nav-underline {\n --bs-nav-underline-gap: 1rem;\n --bs-nav-underline-border-width: 0.125rem;\n --bs-nav-underline-link-active-color: var(--bs-emphasis-color);\n gap: var(--bs-nav-underline-gap);\n}\n.nav-underline .nav-link {\n padding-right: 0;\n padding-left: 0;\n border-bottom: var(--bs-nav-underline-border-width) solid transparent;\n}\n.nav-underline .nav-link:hover, .nav-underline .nav-link:focus {\n border-bottom-color: currentcolor;\n}\n.nav-underline .nav-link.active,\n.nav-underline .show > .nav-link {\n font-weight: 700;\n color: var(--bs-nav-underline-link-active-color);\n border-bottom-color: currentcolor;\n}\n\n.nav-fill > .nav-link,\n.nav-fill .nav-item {\n flex: 1 1 auto;\n text-align: center;\n}\n\n.nav-justified > .nav-link,\n.nav-justified .nav-item {\n flex-basis: 0;\n flex-grow: 1;\n text-align: center;\n}\n\n.nav-fill .nav-item .nav-link,\n.nav-justified .nav-item .nav-link {\n width: 100%;\n}\n\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n\n.navbar {\n --bs-navbar-padding-x: 0;\n --bs-navbar-padding-y: 0.5rem;\n --bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65);\n --bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8);\n --bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3);\n --bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);\n --bs-navbar-brand-padding-y: 0.3125rem;\n --bs-navbar-brand-margin-end: 1rem;\n --bs-navbar-brand-font-size: 1.25rem;\n --bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);\n --bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);\n --bs-navbar-nav-link-padding-x: 0.5rem;\n --bs-navbar-toggler-padding-y: 0.25rem;\n --bs-navbar-toggler-padding-x: 0.75rem;\n --bs-navbar-toggler-font-size: 1.25rem;\n --bs-navbar-toggler-icon-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n --bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15);\n --bs-navbar-toggler-border-radius: var(--bs-border-radius);\n --bs-navbar-toggler-focus-width: 0.25rem;\n --bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding: var(--bs-navbar-padding-y) var(--bs-navbar-padding-x);\n}\n.navbar > .container,\n.navbar > .container-fluid,\n.navbar > .container-sm,\n.navbar > .container-md,\n.navbar > .container-lg,\n.navbar > .container-xl,\n.navbar > .container-xxl {\n display: flex;\n flex-wrap: inherit;\n align-items: center;\n justify-content: space-between;\n}\n.navbar-brand {\n padding-top: var(--bs-navbar-brand-padding-y);\n padding-bottom: var(--bs-navbar-brand-padding-y);\n margin-right: var(--bs-navbar-brand-margin-end);\n font-size: var(--bs-navbar-brand-font-size);\n color: var(--bs-navbar-brand-color);\n text-decoration: none;\n white-space: nowrap;\n}\n.navbar-brand:hover, .navbar-brand:focus {\n color: var(--bs-navbar-brand-hover-color);\n}\n\n.navbar-nav {\n --bs-nav-link-padding-x: 0;\n --bs-nav-link-padding-y: 0.5rem;\n --bs-nav-link-font-weight: ;\n --bs-nav-link-color: var(--bs-navbar-color);\n --bs-nav-link-hover-color: var(--bs-navbar-hover-color);\n --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.navbar-nav .nav-link.active, .navbar-nav .nav-link.show {\n color: var(--bs-navbar-active-color);\n}\n.navbar-nav .dropdown-menu {\n position: static;\n}\n\n.navbar-text {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n color: var(--bs-navbar-color);\n}\n.navbar-text a,\n.navbar-text a:hover,\n.navbar-text a:focus {\n color: var(--bs-navbar-active-color);\n}\n\n.navbar-collapse {\n flex-basis: 100%;\n flex-grow: 1;\n align-items: center;\n}\n\n.navbar-toggler {\n padding: var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);\n font-size: var(--bs-navbar-toggler-font-size);\n line-height: 1;\n color: var(--bs-navbar-color);\n background-color: transparent;\n border: var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);\n border-radius: var(--bs-navbar-toggler-border-radius);\n transition: var(--bs-navbar-toggler-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .navbar-toggler {\n transition: none;\n }\n}\n.navbar-toggler:hover {\n text-decoration: none;\n}\n.navbar-toggler:focus {\n text-decoration: none;\n outline: 0;\n box-shadow: 0 0 0 var(--bs-navbar-toggler-focus-width);\n}\n\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n background-image: var(--bs-navbar-toggler-icon-bg);\n background-repeat: no-repeat;\n background-position: center;\n background-size: 100%;\n}\n\n.navbar-nav-scroll {\n max-height: var(--bs-scroll-height, 75vh);\n overflow-y: auto;\n}\n\n@media (min-width: 576px) {\n .navbar-expand-sm {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-sm .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-sm .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-sm .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-sm .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-sm .navbar-toggler {\n display: none;\n }\n .navbar-expand-sm .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-sm .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-sm .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 768px) {\n .navbar-expand-md {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-md .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-md .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-md .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-md .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-md .navbar-toggler {\n display: none;\n }\n .navbar-expand-md .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-md .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-md .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 992px) {\n .navbar-expand-lg {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-lg .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-lg .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-lg .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-lg .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-lg .navbar-toggler {\n display: none;\n }\n .navbar-expand-lg .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-lg .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-lg .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 1200px) {\n .navbar-expand-xl {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xl .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-xl .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-xl .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-xl .navbar-toggler {\n display: none;\n }\n .navbar-expand-xl .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-xl .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-xl .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 1400px) {\n .navbar-expand-xxl {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xxl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xxl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xxl .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n .navbar-expand-xxl .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-xxl .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-xxl .navbar-toggler {\n display: none;\n }\n .navbar-expand-xxl .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n }\n .navbar-expand-xxl .offcanvas .offcanvas-header {\n display: none;\n }\n .navbar-expand-xxl .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n.navbar-expand {\n flex-wrap: nowrap;\n justify-content: flex-start;\n}\n.navbar-expand .navbar-nav {\n flex-direction: row;\n}\n.navbar-expand .navbar-nav .dropdown-menu {\n position: absolute;\n}\n.navbar-expand .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n}\n.navbar-expand .navbar-nav-scroll {\n overflow: visible;\n}\n.navbar-expand .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n}\n.navbar-expand .navbar-toggler {\n display: none;\n}\n.navbar-expand .offcanvas {\n position: static;\n z-index: auto;\n flex-grow: 1;\n width: auto !important;\n height: auto !important;\n visibility: visible !important;\n background-color: transparent !important;\n border: 0 !important;\n transform: none !important;\n transition: none;\n}\n.navbar-expand .offcanvas .offcanvas-header {\n display: none;\n}\n.navbar-expand .offcanvas .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n}\n\n.navbar-dark,\n.navbar[data-bs-theme=dark] {\n --bs-navbar-color: rgba(255, 255, 255, 0.55);\n --bs-navbar-hover-color: rgba(255, 255, 255, 0.75);\n --bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);\n --bs-navbar-active-color: #fff;\n --bs-navbar-brand-color: #fff;\n --bs-navbar-brand-hover-color: #fff;\n --bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1);\n --bs-navbar-toggler-icon-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n[data-bs-theme=dark] .navbar-toggler-icon {\n --bs-navbar-toggler-icon-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.card {\n --bs-card-spacer-y: 1rem;\n --bs-card-spacer-x: 1rem;\n --bs-card-title-spacer-y: 0.5rem;\n --bs-card-title-color: ;\n --bs-card-subtitle-color: ;\n --bs-card-border-width: var(--bs-border-width);\n --bs-card-border-color: var(--bs-border-color-translucent);\n --bs-card-border-radius: var(--bs-border-radius);\n --bs-card-box-shadow: ;\n --bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));\n --bs-card-cap-padding-y: 0.5rem;\n --bs-card-cap-padding-x: 1rem;\n --bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03);\n --bs-card-cap-color: ;\n --bs-card-height: ;\n --bs-card-color: ;\n --bs-card-bg: var(--bs-body-bg);\n --bs-card-img-overlay-padding: 1rem;\n --bs-card-group-margin: 0.75rem;\n position: relative;\n display: flex;\n flex-direction: column;\n min-width: 0;\n height: var(--bs-card-height);\n color: var(--bs-body-color);\n word-wrap: break-word;\n background-color: var(--bs-card-bg);\n background-clip: border-box;\n border: var(--bs-card-border-width) solid var(--bs-card-border-color);\n border-radius: var(--bs-card-border-radius);\n}\n.card > hr {\n margin-right: 0;\n margin-left: 0;\n}\n.card > .list-group {\n border-top: inherit;\n border-bottom: inherit;\n}\n.card > .list-group:first-child {\n border-top-width: 0;\n border-top-left-radius: var(--bs-card-inner-border-radius);\n border-top-right-radius: var(--bs-card-inner-border-radius);\n}\n.card > .list-group:last-child {\n border-bottom-width: 0;\n border-bottom-right-radius: var(--bs-card-inner-border-radius);\n border-bottom-left-radius: var(--bs-card-inner-border-radius);\n}\n.card > .card-header + .list-group,\n.card > .list-group + .card-footer {\n border-top: 0;\n}\n\n.card-body {\n flex: 1 1 auto;\n padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x);\n color: var(--bs-card-color);\n}\n\n.card-title {\n margin-bottom: var(--bs-card-title-spacer-y);\n color: var(--bs-card-title-color);\n}\n\n.card-subtitle {\n margin-top: calc(-0.5 * var(--bs-card-title-spacer-y));\n margin-bottom: 0;\n color: var(--bs-card-subtitle-color);\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link + .card-link {\n margin-left: var(--bs-card-spacer-x);\n}\n\n.card-header {\n padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);\n margin-bottom: 0;\n color: var(--bs-card-cap-color);\n background-color: var(--bs-card-cap-bg);\n border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color);\n}\n.card-header:first-child {\n border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0;\n}\n\n.card-footer {\n padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);\n color: var(--bs-card-cap-color);\n background-color: var(--bs-card-cap-bg);\n border-top: var(--bs-card-border-width) solid var(--bs-card-border-color);\n}\n.card-footer:last-child {\n border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius);\n}\n\n.card-header-tabs {\n margin-right: calc(-0.5 * var(--bs-card-cap-padding-x));\n margin-bottom: calc(-1 * var(--bs-card-cap-padding-y));\n margin-left: calc(-0.5 * var(--bs-card-cap-padding-x));\n border-bottom: 0;\n}\n.card-header-tabs .nav-link.active {\n background-color: var(--bs-card-bg);\n border-bottom-color: var(--bs-card-bg);\n}\n\n.card-header-pills {\n margin-right: calc(-0.5 * var(--bs-card-cap-padding-x));\n margin-left: calc(-0.5 * var(--bs-card-cap-padding-x));\n}\n\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: var(--bs-card-img-overlay-padding);\n border-radius: var(--bs-card-inner-border-radius);\n}\n\n.card-img,\n.card-img-top,\n.card-img-bottom {\n width: 100%;\n}\n\n.card-img,\n.card-img-top {\n border-top-left-radius: var(--bs-card-inner-border-radius);\n border-top-right-radius: var(--bs-card-inner-border-radius);\n}\n\n.card-img,\n.card-img-bottom {\n border-bottom-right-radius: var(--bs-card-inner-border-radius);\n border-bottom-left-radius: var(--bs-card-inner-border-radius);\n}\n\n.card-group > .card {\n margin-bottom: var(--bs-card-group-margin);\n}\n@media (min-width: 576px) {\n .card-group {\n display: flex;\n flex-flow: row wrap;\n }\n .card-group > .card {\n flex: 1 0 0%;\n margin-bottom: 0;\n }\n .card-group > .card + .card {\n margin-left: 0;\n border-left: 0;\n }\n .card-group > .card:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-top,\n .card-group > .card:not(:last-child) .card-header {\n border-top-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-bottom,\n .card-group > .card:not(:last-child) .card-footer {\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-top,\n .card-group > .card:not(:first-child) .card-header {\n border-top-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-bottom,\n .card-group > .card:not(:first-child) .card-footer {\n border-bottom-left-radius: 0;\n }\n}\n\n.accordion {\n --bs-accordion-color: var(--bs-body-color);\n --bs-accordion-bg: var(--bs-body-bg);\n --bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;\n --bs-accordion-border-color: var(--bs-border-color);\n --bs-accordion-border-width: var(--bs-border-width);\n --bs-accordion-border-radius: var(--bs-border-radius);\n --bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));\n --bs-accordion-btn-padding-x: 1.25rem;\n --bs-accordion-btn-padding-y: 1rem;\n --bs-accordion-btn-color: var(--bs-body-color);\n --bs-accordion-btn-bg: var(--bs-accordion-bg);\n --bs-accordion-btn-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n --bs-accordion-btn-icon-width: 1.25rem;\n --bs-accordion-btn-icon-transform: rotate(-180deg);\n --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;\n --bs-accordion-btn-active-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n --bs-accordion-btn-focus-border-color: #86b7fe;\n --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n --bs-accordion-body-padding-x: 1.25rem;\n --bs-accordion-body-padding-y: 1rem;\n --bs-accordion-active-color: var(--bs-primary-text-emphasis);\n --bs-accordion-active-bg: var(--bs-primary-bg-subtle);\n}\n\n.accordion-button {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);\n font-size: 1rem;\n color: var(--bs-accordion-btn-color);\n text-align: left;\n background-color: var(--bs-accordion-btn-bg);\n border: 0;\n border-radius: 0;\n overflow-anchor: none;\n transition: var(--bs-accordion-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .accordion-button {\n transition: none;\n }\n}\n.accordion-button:not(.collapsed) {\n color: var(--bs-accordion-active-color);\n background-color: var(--bs-accordion-active-bg);\n box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color);\n}\n.accordion-button:not(.collapsed)::after {\n background-image: var(--bs-accordion-btn-active-icon);\n transform: var(--bs-accordion-btn-icon-transform);\n}\n.accordion-button::after {\n flex-shrink: 0;\n width: var(--bs-accordion-btn-icon-width);\n height: var(--bs-accordion-btn-icon-width);\n margin-left: auto;\n content: \"\";\n background-image: var(--bs-accordion-btn-icon);\n background-repeat: no-repeat;\n background-size: var(--bs-accordion-btn-icon-width);\n transition: var(--bs-accordion-btn-icon-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .accordion-button::after {\n transition: none;\n }\n}\n.accordion-button:hover {\n z-index: 2;\n}\n.accordion-button:focus {\n z-index: 3;\n border-color: var(--bs-accordion-btn-focus-border-color);\n outline: 0;\n box-shadow: var(--bs-accordion-btn-focus-box-shadow);\n}\n\n.accordion-header {\n margin-bottom: 0;\n}\n\n.accordion-item {\n color: var(--bs-accordion-color);\n background-color: var(--bs-accordion-bg);\n border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color);\n}\n.accordion-item:first-of-type {\n border-top-left-radius: var(--bs-accordion-border-radius);\n border-top-right-radius: var(--bs-accordion-border-radius);\n}\n.accordion-item:first-of-type .accordion-button {\n border-top-left-radius: var(--bs-accordion-inner-border-radius);\n border-top-right-radius: var(--bs-accordion-inner-border-radius);\n}\n.accordion-item:not(:first-of-type) {\n border-top: 0;\n}\n.accordion-item:last-of-type {\n border-bottom-right-radius: var(--bs-accordion-border-radius);\n border-bottom-left-radius: var(--bs-accordion-border-radius);\n}\n.accordion-item:last-of-type .accordion-button.collapsed {\n border-bottom-right-radius: var(--bs-accordion-inner-border-radius);\n border-bottom-left-radius: var(--bs-accordion-inner-border-radius);\n}\n.accordion-item:last-of-type .accordion-collapse {\n border-bottom-right-radius: var(--bs-accordion-border-radius);\n border-bottom-left-radius: var(--bs-accordion-border-radius);\n}\n\n.accordion-body {\n padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x);\n}\n\n.accordion-flush .accordion-collapse {\n border-width: 0;\n}\n.accordion-flush .accordion-item {\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n.accordion-flush .accordion-item:first-child {\n border-top: 0;\n}\n.accordion-flush .accordion-item:last-child {\n border-bottom: 0;\n}\n.accordion-flush .accordion-item .accordion-button, .accordion-flush .accordion-item .accordion-button.collapsed {\n border-radius: 0;\n}\n\n[data-bs-theme=dark] .accordion-button::after {\n --bs-accordion-btn-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n --bs-accordion-btn-active-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n}\n\n.breadcrumb {\n --bs-breadcrumb-padding-x: 0;\n --bs-breadcrumb-padding-y: 0;\n --bs-breadcrumb-margin-bottom: 1rem;\n --bs-breadcrumb-bg: ;\n --bs-breadcrumb-border-radius: ;\n --bs-breadcrumb-divider-color: var(--bs-secondary-color);\n --bs-breadcrumb-item-padding-x: 0.5rem;\n --bs-breadcrumb-item-active-color: var(--bs-secondary-color);\n display: flex;\n flex-wrap: wrap;\n padding: var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);\n margin-bottom: var(--bs-breadcrumb-margin-bottom);\n font-size: var(--bs-breadcrumb-font-size);\n list-style: none;\n background-color: var(--bs-breadcrumb-bg);\n border-radius: var(--bs-breadcrumb-border-radius);\n}\n\n.breadcrumb-item + .breadcrumb-item {\n padding-left: var(--bs-breadcrumb-item-padding-x);\n}\n.breadcrumb-item + .breadcrumb-item::before {\n float: left;\n padding-right: var(--bs-breadcrumb-item-padding-x);\n color: var(--bs-breadcrumb-divider-color);\n content: var(--bs-breadcrumb-divider, \"/\") /* rtl: var(--bs-breadcrumb-divider, \"/\") */;\n}\n.breadcrumb-item.active {\n color: var(--bs-breadcrumb-item-active-color);\n}\n\n.pagination {\n --bs-pagination-padding-x: 0.75rem;\n --bs-pagination-padding-y: 0.375rem;\n --bs-pagination-font-size: 1rem;\n --bs-pagination-color: var(--bs-link-color);\n --bs-pagination-bg: var(--bs-body-bg);\n --bs-pagination-border-width: var(--bs-border-width);\n --bs-pagination-border-color: var(--bs-border-color);\n --bs-pagination-border-radius: var(--bs-border-radius);\n --bs-pagination-hover-color: var(--bs-link-hover-color);\n --bs-pagination-hover-bg: var(--bs-tertiary-bg);\n --bs-pagination-hover-border-color: var(--bs-border-color);\n --bs-pagination-focus-color: var(--bs-link-hover-color);\n --bs-pagination-focus-bg: var(--bs-secondary-bg);\n --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n --bs-pagination-active-color: #fff;\n --bs-pagination-active-bg: #0d6efd;\n --bs-pagination-active-border-color: #0d6efd;\n --bs-pagination-disabled-color: var(--bs-secondary-color);\n --bs-pagination-disabled-bg: var(--bs-secondary-bg);\n --bs-pagination-disabled-border-color: var(--bs-border-color);\n display: flex;\n padding-left: 0;\n list-style: none;\n}\n\n.page-link {\n position: relative;\n display: block;\n padding: var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);\n font-size: var(--bs-pagination-font-size);\n color: var(--bs-pagination-color);\n text-decoration: none;\n background-color: var(--bs-pagination-bg);\n border: var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .page-link {\n transition: none;\n }\n}\n.page-link:hover {\n z-index: 2;\n color: var(--bs-pagination-hover-color);\n background-color: var(--bs-pagination-hover-bg);\n border-color: var(--bs-pagination-hover-border-color);\n}\n.page-link:focus {\n z-index: 3;\n color: var(--bs-pagination-focus-color);\n background-color: var(--bs-pagination-focus-bg);\n outline: 0;\n box-shadow: var(--bs-pagination-focus-box-shadow);\n}\n.page-link.active, .active > .page-link {\n z-index: 3;\n color: var(--bs-pagination-active-color);\n background-color: var(--bs-pagination-active-bg);\n border-color: var(--bs-pagination-active-border-color);\n}\n.page-link.disabled, .disabled > .page-link {\n color: var(--bs-pagination-disabled-color);\n pointer-events: none;\n background-color: var(--bs-pagination-disabled-bg);\n border-color: var(--bs-pagination-disabled-border-color);\n}\n\n.page-item:not(:first-child) .page-link {\n margin-left: calc(var(--bs-border-width) * -1);\n}\n.page-item:first-child .page-link {\n border-top-left-radius: var(--bs-pagination-border-radius);\n border-bottom-left-radius: var(--bs-pagination-border-radius);\n}\n.page-item:last-child .page-link {\n border-top-right-radius: var(--bs-pagination-border-radius);\n border-bottom-right-radius: var(--bs-pagination-border-radius);\n}\n\n.pagination-lg {\n --bs-pagination-padding-x: 1.5rem;\n --bs-pagination-padding-y: 0.75rem;\n --bs-pagination-font-size: 1.25rem;\n --bs-pagination-border-radius: var(--bs-border-radius-lg);\n}\n\n.pagination-sm {\n --bs-pagination-padding-x: 0.5rem;\n --bs-pagination-padding-y: 0.25rem;\n --bs-pagination-font-size: 0.875rem;\n --bs-pagination-border-radius: var(--bs-border-radius-sm);\n}\n\n.badge {\n --bs-badge-padding-x: 0.65em;\n --bs-badge-padding-y: 0.35em;\n --bs-badge-font-size: 0.75em;\n --bs-badge-font-weight: 700;\n --bs-badge-color: #fff;\n --bs-badge-border-radius: var(--bs-border-radius);\n display: inline-block;\n padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x);\n font-size: var(--bs-badge-font-size);\n font-weight: var(--bs-badge-font-weight);\n line-height: 1;\n color: var(--bs-badge-color);\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: var(--bs-badge-border-radius);\n}\n.badge:empty {\n display: none;\n}\n\n.btn .badge {\n position: relative;\n top: -1px;\n}\n\n.alert {\n --bs-alert-bg: transparent;\n --bs-alert-padding-x: 1rem;\n --bs-alert-padding-y: 1rem;\n --bs-alert-margin-bottom: 1rem;\n --bs-alert-color: inherit;\n --bs-alert-border-color: transparent;\n --bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);\n --bs-alert-border-radius: var(--bs-border-radius);\n --bs-alert-link-color: inherit;\n position: relative;\n padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x);\n margin-bottom: var(--bs-alert-margin-bottom);\n color: var(--bs-alert-color);\n background-color: var(--bs-alert-bg);\n border: var(--bs-alert-border);\n border-radius: var(--bs-alert-border-radius);\n}\n\n.alert-heading {\n color: inherit;\n}\n\n.alert-link {\n font-weight: 700;\n color: var(--bs-alert-link-color);\n}\n\n.alert-dismissible {\n padding-right: 3rem;\n}\n.alert-dismissible .btn-close {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n padding: 1.25rem 1rem;\n}\n\n.alert-primary {\n --bs-alert-color: var(--bs-primary-text-emphasis);\n --bs-alert-bg: var(--bs-primary-bg-subtle);\n --bs-alert-border-color: var(--bs-primary-border-subtle);\n --bs-alert-link-color: var(--bs-primary-text-emphasis);\n}\n\n.alert-secondary {\n --bs-alert-color: var(--bs-secondary-text-emphasis);\n --bs-alert-bg: var(--bs-secondary-bg-subtle);\n --bs-alert-border-color: var(--bs-secondary-border-subtle);\n --bs-alert-link-color: var(--bs-secondary-text-emphasis);\n}\n\n.alert-success {\n --bs-alert-color: var(--bs-success-text-emphasis);\n --bs-alert-bg: var(--bs-success-bg-subtle);\n --bs-alert-border-color: var(--bs-success-border-subtle);\n --bs-alert-link-color: var(--bs-success-text-emphasis);\n}\n\n.alert-info {\n --bs-alert-color: var(--bs-info-text-emphasis);\n --bs-alert-bg: var(--bs-info-bg-subtle);\n --bs-alert-border-color: var(--bs-info-border-subtle);\n --bs-alert-link-color: var(--bs-info-text-emphasis);\n}\n\n.alert-warning {\n --bs-alert-color: var(--bs-warning-text-emphasis);\n --bs-alert-bg: var(--bs-warning-bg-subtle);\n --bs-alert-border-color: var(--bs-warning-border-subtle);\n --bs-alert-link-color: var(--bs-warning-text-emphasis);\n}\n\n.alert-danger {\n --bs-alert-color: var(--bs-danger-text-emphasis);\n --bs-alert-bg: var(--bs-danger-bg-subtle);\n --bs-alert-border-color: var(--bs-danger-border-subtle);\n --bs-alert-link-color: var(--bs-danger-text-emphasis);\n}\n\n.alert-light {\n --bs-alert-color: var(--bs-light-text-emphasis);\n --bs-alert-bg: var(--bs-light-bg-subtle);\n --bs-alert-border-color: var(--bs-light-border-subtle);\n --bs-alert-link-color: var(--bs-light-text-emphasis);\n}\n\n.alert-dark {\n --bs-alert-color: var(--bs-dark-text-emphasis);\n --bs-alert-bg: var(--bs-dark-bg-subtle);\n --bs-alert-border-color: var(--bs-dark-border-subtle);\n --bs-alert-link-color: var(--bs-dark-text-emphasis);\n}\n\n@keyframes progress-bar-stripes {\n 0% {\n background-position-x: 1rem;\n }\n}\n.progress,\n.progress-stacked {\n --bs-progress-height: 1rem;\n --bs-progress-font-size: 0.75rem;\n --bs-progress-bg: var(--bs-secondary-bg);\n --bs-progress-border-radius: var(--bs-border-radius);\n --bs-progress-box-shadow: var(--bs-box-shadow-inset);\n --bs-progress-bar-color: #fff;\n --bs-progress-bar-bg: #0d6efd;\n --bs-progress-bar-transition: width 0.6s ease;\n display: flex;\n height: var(--bs-progress-height);\n overflow: hidden;\n font-size: var(--bs-progress-font-size);\n background-color: var(--bs-progress-bg);\n border-radius: var(--bs-progress-border-radius);\n}\n\n.progress-bar {\n display: flex;\n flex-direction: column;\n justify-content: center;\n overflow: hidden;\n color: var(--bs-progress-bar-color);\n text-align: center;\n white-space: nowrap;\n background-color: var(--bs-progress-bar-bg);\n transition: var(--bs-progress-bar-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .progress-bar {\n transition: none;\n }\n}\n\n.progress-bar-striped {\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: var(--bs-progress-height) var(--bs-progress-height);\n}\n\n.progress-stacked > .progress {\n overflow: visible;\n}\n\n.progress-stacked > .progress > .progress-bar {\n width: 100%;\n}\n\n.progress-bar-animated {\n animation: 1s linear infinite progress-bar-stripes;\n}\n@media (prefers-reduced-motion: reduce) {\n .progress-bar-animated {\n animation: none;\n }\n}\n\n.list-group {\n --bs-list-group-color: var(--bs-body-color);\n --bs-list-group-bg: var(--bs-body-bg);\n --bs-list-group-border-color: var(--bs-border-color);\n --bs-list-group-border-width: var(--bs-border-width);\n --bs-list-group-border-radius: var(--bs-border-radius);\n --bs-list-group-item-padding-x: 1rem;\n --bs-list-group-item-padding-y: 0.5rem;\n --bs-list-group-action-color: var(--bs-secondary-color);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-tertiary-bg);\n --bs-list-group-action-active-color: var(--bs-body-color);\n --bs-list-group-action-active-bg: var(--bs-secondary-bg);\n --bs-list-group-disabled-color: var(--bs-secondary-color);\n --bs-list-group-disabled-bg: var(--bs-body-bg);\n --bs-list-group-active-color: #fff;\n --bs-list-group-active-bg: #0d6efd;\n --bs-list-group-active-border-color: #0d6efd;\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n border-radius: var(--bs-list-group-border-radius);\n}\n\n.list-group-numbered {\n list-style-type: none;\n counter-reset: section;\n}\n.list-group-numbered > .list-group-item::before {\n content: counters(section, \".\") \". \";\n counter-increment: section;\n}\n\n.list-group-item-action {\n width: 100%;\n color: var(--bs-list-group-action-color);\n text-align: inherit;\n}\n.list-group-item-action:hover, .list-group-item-action:focus {\n z-index: 1;\n color: var(--bs-list-group-action-hover-color);\n text-decoration: none;\n background-color: var(--bs-list-group-action-hover-bg);\n}\n.list-group-item-action:active {\n color: var(--bs-list-group-action-active-color);\n background-color: var(--bs-list-group-action-active-bg);\n}\n\n.list-group-item {\n position: relative;\n display: block;\n padding: var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);\n color: var(--bs-list-group-color);\n text-decoration: none;\n background-color: var(--bs-list-group-bg);\n border: var(--bs-list-group-border-width) solid var(--bs-list-group-border-color);\n}\n.list-group-item:first-child {\n border-top-left-radius: inherit;\n border-top-right-radius: inherit;\n}\n.list-group-item:last-child {\n border-bottom-right-radius: inherit;\n border-bottom-left-radius: inherit;\n}\n.list-group-item.disabled, .list-group-item:disabled {\n color: var(--bs-list-group-disabled-color);\n pointer-events: none;\n background-color: var(--bs-list-group-disabled-bg);\n}\n.list-group-item.active {\n z-index: 2;\n color: var(--bs-list-group-active-color);\n background-color: var(--bs-list-group-active-bg);\n border-color: var(--bs-list-group-active-border-color);\n}\n.list-group-item + .list-group-item {\n border-top-width: 0;\n}\n.list-group-item + .list-group-item.active {\n margin-top: calc(-1 * var(--bs-list-group-border-width));\n border-top-width: var(--bs-list-group-border-width);\n}\n\n.list-group-horizontal {\n flex-direction: row;\n}\n.list-group-horizontal > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n}\n.list-group-horizontal > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n}\n.list-group-horizontal > .list-group-item.active {\n margin-top: 0;\n}\n.list-group-horizontal > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n}\n.list-group-horizontal > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n}\n\n@media (min-width: 576px) {\n .list-group-horizontal-sm {\n flex-direction: row;\n }\n .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-sm > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-sm > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-sm > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 768px) {\n .list-group-horizontal-md {\n flex-direction: row;\n }\n .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-md > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-md > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-md > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 992px) {\n .list-group-horizontal-lg {\n flex-direction: row;\n }\n .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-lg > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-lg > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-lg > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 1200px) {\n .list-group-horizontal-xl {\n flex-direction: row;\n }\n .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-xl > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-xl > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-xl > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n@media (min-width: 1400px) {\n .list-group-horizontal-xxl {\n flex-direction: row;\n }\n .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) {\n border-bottom-left-radius: var(--bs-list-group-border-radius);\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) {\n border-top-right-radius: var(--bs-list-group-border-radius);\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-xxl > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-xxl > .list-group-item + .list-group-item {\n border-top-width: var(--bs-list-group-border-width);\n border-left-width: 0;\n }\n .list-group-horizontal-xxl > .list-group-item + .list-group-item.active {\n margin-left: calc(-1 * var(--bs-list-group-border-width));\n border-left-width: var(--bs-list-group-border-width);\n }\n}\n.list-group-flush {\n border-radius: 0;\n}\n.list-group-flush > .list-group-item {\n border-width: 0 0 var(--bs-list-group-border-width);\n}\n.list-group-flush > .list-group-item:last-child {\n border-bottom-width: 0;\n}\n\n.list-group-item-primary {\n --bs-list-group-color: var(--bs-primary-text-emphasis);\n --bs-list-group-bg: var(--bs-primary-bg-subtle);\n --bs-list-group-border-color: var(--bs-primary-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-primary-border-subtle);\n --bs-list-group-active-color: var(--bs-primary-bg-subtle);\n --bs-list-group-active-bg: var(--bs-primary-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-primary-text-emphasis);\n}\n\n.list-group-item-secondary {\n --bs-list-group-color: var(--bs-secondary-text-emphasis);\n --bs-list-group-bg: var(--bs-secondary-bg-subtle);\n --bs-list-group-border-color: var(--bs-secondary-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);\n --bs-list-group-active-color: var(--bs-secondary-bg-subtle);\n --bs-list-group-active-bg: var(--bs-secondary-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-secondary-text-emphasis);\n}\n\n.list-group-item-success {\n --bs-list-group-color: var(--bs-success-text-emphasis);\n --bs-list-group-bg: var(--bs-success-bg-subtle);\n --bs-list-group-border-color: var(--bs-success-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-success-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-success-border-subtle);\n --bs-list-group-active-color: var(--bs-success-bg-subtle);\n --bs-list-group-active-bg: var(--bs-success-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-success-text-emphasis);\n}\n\n.list-group-item-info {\n --bs-list-group-color: var(--bs-info-text-emphasis);\n --bs-list-group-bg: var(--bs-info-bg-subtle);\n --bs-list-group-border-color: var(--bs-info-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-info-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-info-border-subtle);\n --bs-list-group-active-color: var(--bs-info-bg-subtle);\n --bs-list-group-active-bg: var(--bs-info-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-info-text-emphasis);\n}\n\n.list-group-item-warning {\n --bs-list-group-color: var(--bs-warning-text-emphasis);\n --bs-list-group-bg: var(--bs-warning-bg-subtle);\n --bs-list-group-border-color: var(--bs-warning-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-warning-border-subtle);\n --bs-list-group-active-color: var(--bs-warning-bg-subtle);\n --bs-list-group-active-bg: var(--bs-warning-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-warning-text-emphasis);\n}\n\n.list-group-item-danger {\n --bs-list-group-color: var(--bs-danger-text-emphasis);\n --bs-list-group-bg: var(--bs-danger-bg-subtle);\n --bs-list-group-border-color: var(--bs-danger-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-danger-border-subtle);\n --bs-list-group-active-color: var(--bs-danger-bg-subtle);\n --bs-list-group-active-bg: var(--bs-danger-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-danger-text-emphasis);\n}\n\n.list-group-item-light {\n --bs-list-group-color: var(--bs-light-text-emphasis);\n --bs-list-group-bg: var(--bs-light-bg-subtle);\n --bs-list-group-border-color: var(--bs-light-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-light-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-light-border-subtle);\n --bs-list-group-active-color: var(--bs-light-bg-subtle);\n --bs-list-group-active-bg: var(--bs-light-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-light-text-emphasis);\n}\n\n.list-group-item-dark {\n --bs-list-group-color: var(--bs-dark-text-emphasis);\n --bs-list-group-bg: var(--bs-dark-bg-subtle);\n --bs-list-group-border-color: var(--bs-dark-border-subtle);\n --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n --bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);\n --bs-list-group-action-active-color: var(--bs-emphasis-color);\n --bs-list-group-action-active-bg: var(--bs-dark-border-subtle);\n --bs-list-group-active-color: var(--bs-dark-bg-subtle);\n --bs-list-group-active-bg: var(--bs-dark-text-emphasis);\n --bs-list-group-active-border-color: var(--bs-dark-text-emphasis);\n}\n\n.btn-close {\n --bs-btn-close-color: #000;\n --bs-btn-close-bg: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e\");\n --bs-btn-close-opacity: 0.5;\n --bs-btn-close-hover-opacity: 0.75;\n --bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n --bs-btn-close-focus-opacity: 1;\n --bs-btn-close-disabled-opacity: 0.25;\n --bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);\n box-sizing: content-box;\n width: 1em;\n height: 1em;\n padding: 0.25em 0.25em;\n color: var(--bs-btn-close-color);\n background: transparent var(--bs-btn-close-bg) center/1em auto no-repeat;\n border: 0;\n border-radius: 0.375rem;\n opacity: var(--bs-btn-close-opacity);\n}\n.btn-close:hover {\n color: var(--bs-btn-close-color);\n text-decoration: none;\n opacity: var(--bs-btn-close-hover-opacity);\n}\n.btn-close:focus {\n outline: 0;\n box-shadow: var(--bs-btn-close-focus-shadow);\n opacity: var(--bs-btn-close-focus-opacity);\n}\n.btn-close:disabled, .btn-close.disabled {\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n opacity: var(--bs-btn-close-disabled-opacity);\n}\n\n.btn-close-white {\n filter: var(--bs-btn-close-white-filter);\n}\n\n[data-bs-theme=dark] .btn-close {\n filter: var(--bs-btn-close-white-filter);\n}\n\n.toast {\n --bs-toast-zindex: 1090;\n --bs-toast-padding-x: 0.75rem;\n --bs-toast-padding-y: 0.5rem;\n --bs-toast-spacing: 1.5rem;\n --bs-toast-max-width: 350px;\n --bs-toast-font-size: 0.875rem;\n --bs-toast-color: ;\n --bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85);\n --bs-toast-border-width: var(--bs-border-width);\n --bs-toast-border-color: var(--bs-border-color-translucent);\n --bs-toast-border-radius: var(--bs-border-radius);\n --bs-toast-box-shadow: var(--bs-box-shadow);\n --bs-toast-header-color: var(--bs-secondary-color);\n --bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85);\n --bs-toast-header-border-color: var(--bs-border-color-translucent);\n width: var(--bs-toast-max-width);\n max-width: 100%;\n font-size: var(--bs-toast-font-size);\n color: var(--bs-toast-color);\n pointer-events: auto;\n background-color: var(--bs-toast-bg);\n background-clip: padding-box;\n border: var(--bs-toast-border-width) solid var(--bs-toast-border-color);\n box-shadow: var(--bs-toast-box-shadow);\n border-radius: var(--bs-toast-border-radius);\n}\n.toast.showing {\n opacity: 0;\n}\n.toast:not(.show) {\n display: none;\n}\n\n.toast-container {\n --bs-toast-zindex: 1090;\n position: absolute;\n z-index: var(--bs-toast-zindex);\n width: -webkit-max-content;\n width: -moz-max-content;\n width: max-content;\n max-width: 100%;\n pointer-events: none;\n}\n.toast-container > :not(:last-child) {\n margin-bottom: var(--bs-toast-spacing);\n}\n\n.toast-header {\n display: flex;\n align-items: center;\n padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x);\n color: var(--bs-toast-header-color);\n background-color: var(--bs-toast-header-bg);\n background-clip: padding-box;\n border-bottom: var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);\n border-top-left-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));\n border-top-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));\n}\n.toast-header .btn-close {\n margin-right: calc(-0.5 * var(--bs-toast-padding-x));\n margin-left: var(--bs-toast-padding-x);\n}\n\n.toast-body {\n padding: var(--bs-toast-padding-x);\n word-wrap: break-word;\n}\n\n.modal {\n --bs-modal-zindex: 1055;\n --bs-modal-width: 500px;\n --bs-modal-padding: 1rem;\n --bs-modal-margin: 0.5rem;\n --bs-modal-color: ;\n --bs-modal-bg: var(--bs-body-bg);\n --bs-modal-border-color: var(--bs-border-color-translucent);\n --bs-modal-border-width: var(--bs-border-width);\n --bs-modal-border-radius: var(--bs-border-radius-lg);\n --bs-modal-box-shadow: var(--bs-box-shadow-sm);\n --bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));\n --bs-modal-header-padding-x: 1rem;\n --bs-modal-header-padding-y: 1rem;\n --bs-modal-header-padding: 1rem 1rem;\n --bs-modal-header-border-color: var(--bs-border-color);\n --bs-modal-header-border-width: var(--bs-border-width);\n --bs-modal-title-line-height: 1.5;\n --bs-modal-footer-gap: 0.5rem;\n --bs-modal-footer-bg: ;\n --bs-modal-footer-border-color: var(--bs-border-color);\n --bs-modal-footer-border-width: var(--bs-border-width);\n position: fixed;\n top: 0;\n left: 0;\n z-index: var(--bs-modal-zindex);\n display: none;\n width: 100%;\n height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n outline: 0;\n}\n\n.modal-dialog {\n position: relative;\n width: auto;\n margin: var(--bs-modal-margin);\n pointer-events: none;\n}\n.modal.fade .modal-dialog {\n transition: transform 0.3s ease-out;\n transform: translate(0, -50px);\n}\n@media (prefers-reduced-motion: reduce) {\n .modal.fade .modal-dialog {\n transition: none;\n }\n}\n.modal.show .modal-dialog {\n transform: none;\n}\n.modal.modal-static .modal-dialog {\n transform: scale(1.02);\n}\n\n.modal-dialog-scrollable {\n height: calc(100% - var(--bs-modal-margin) * 2);\n}\n.modal-dialog-scrollable .modal-content {\n max-height: 100%;\n overflow: hidden;\n}\n.modal-dialog-scrollable .modal-body {\n overflow-y: auto;\n}\n\n.modal-dialog-centered {\n display: flex;\n align-items: center;\n min-height: calc(100% - var(--bs-modal-margin) * 2);\n}\n\n.modal-content {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n color: var(--bs-modal-color);\n pointer-events: auto;\n background-color: var(--bs-modal-bg);\n background-clip: padding-box;\n border: var(--bs-modal-border-width) solid var(--bs-modal-border-color);\n border-radius: var(--bs-modal-border-radius);\n outline: 0;\n}\n\n.modal-backdrop {\n --bs-backdrop-zindex: 1050;\n --bs-backdrop-bg: #000;\n --bs-backdrop-opacity: 0.5;\n position: fixed;\n top: 0;\n left: 0;\n z-index: var(--bs-backdrop-zindex);\n width: 100vw;\n height: 100vh;\n background-color: var(--bs-backdrop-bg);\n}\n.modal-backdrop.fade {\n opacity: 0;\n}\n.modal-backdrop.show {\n opacity: var(--bs-backdrop-opacity);\n}\n\n.modal-header {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: space-between;\n padding: var(--bs-modal-header-padding);\n border-bottom: var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);\n border-top-left-radius: var(--bs-modal-inner-border-radius);\n border-top-right-radius: var(--bs-modal-inner-border-radius);\n}\n.modal-header .btn-close {\n padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5);\n margin: calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x)) calc(-0.5 * var(--bs-modal-header-padding-y)) auto;\n}\n\n.modal-title {\n margin-bottom: 0;\n line-height: var(--bs-modal-title-line-height);\n}\n\n.modal-body {\n position: relative;\n flex: 1 1 auto;\n padding: var(--bs-modal-padding);\n}\n\n.modal-footer {\n display: flex;\n flex-shrink: 0;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n padding: calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * 0.5);\n background-color: var(--bs-modal-footer-bg);\n border-top: var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);\n border-bottom-right-radius: var(--bs-modal-inner-border-radius);\n border-bottom-left-radius: var(--bs-modal-inner-border-radius);\n}\n.modal-footer > * {\n margin: calc(var(--bs-modal-footer-gap) * 0.5);\n}\n\n@media (min-width: 576px) {\n .modal {\n --bs-modal-margin: 1.75rem;\n --bs-modal-box-shadow: var(--bs-box-shadow);\n }\n .modal-dialog {\n max-width: var(--bs-modal-width);\n margin-right: auto;\n margin-left: auto;\n }\n .modal-sm {\n --bs-modal-width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg,\n .modal-xl {\n --bs-modal-width: 800px;\n }\n}\n@media (min-width: 1200px) {\n .modal-xl {\n --bs-modal-width: 1140px;\n }\n}\n.modal-fullscreen {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n}\n.modal-fullscreen .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n}\n.modal-fullscreen .modal-header,\n.modal-fullscreen .modal-footer {\n border-radius: 0;\n}\n.modal-fullscreen .modal-body {\n overflow-y: auto;\n}\n\n@media (max-width: 575.98px) {\n .modal-fullscreen-sm-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-sm-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-sm-down .modal-header,\n .modal-fullscreen-sm-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-sm-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 767.98px) {\n .modal-fullscreen-md-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-md-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-md-down .modal-header,\n .modal-fullscreen-md-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-md-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 991.98px) {\n .modal-fullscreen-lg-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-lg-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-lg-down .modal-header,\n .modal-fullscreen-lg-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-lg-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 1199.98px) {\n .modal-fullscreen-xl-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-xl-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-xl-down .modal-header,\n .modal-fullscreen-xl-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-xl-down .modal-body {\n overflow-y: auto;\n }\n}\n@media (max-width: 1399.98px) {\n .modal-fullscreen-xxl-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-xxl-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-xxl-down .modal-header,\n .modal-fullscreen-xxl-down .modal-footer {\n border-radius: 0;\n }\n .modal-fullscreen-xxl-down .modal-body {\n overflow-y: auto;\n }\n}\n.tooltip {\n --bs-tooltip-zindex: 1080;\n --bs-tooltip-max-width: 200px;\n --bs-tooltip-padding-x: 0.5rem;\n --bs-tooltip-padding-y: 0.25rem;\n --bs-tooltip-margin: ;\n --bs-tooltip-font-size: 0.875rem;\n --bs-tooltip-color: var(--bs-body-bg);\n --bs-tooltip-bg: var(--bs-emphasis-color);\n --bs-tooltip-border-radius: var(--bs-border-radius);\n --bs-tooltip-opacity: 0.9;\n --bs-tooltip-arrow-width: 0.8rem;\n --bs-tooltip-arrow-height: 0.4rem;\n z-index: var(--bs-tooltip-zindex);\n display: block;\n margin: var(--bs-tooltip-margin);\n font-family: var(--bs-font-sans-serif);\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n white-space: normal;\n word-spacing: normal;\n line-break: auto;\n font-size: var(--bs-tooltip-font-size);\n word-wrap: break-word;\n opacity: 0;\n}\n.tooltip.show {\n opacity: var(--bs-tooltip-opacity);\n}\n.tooltip .tooltip-arrow {\n display: block;\n width: var(--bs-tooltip-arrow-width);\n height: var(--bs-tooltip-arrow-height);\n}\n.tooltip .tooltip-arrow::before {\n position: absolute;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow {\n bottom: calc(-1 * var(--bs-tooltip-arrow-height));\n}\n.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before {\n top: -1px;\n border-width: var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0;\n border-top-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow {\n left: calc(-1 * var(--bs-tooltip-arrow-height));\n width: var(--bs-tooltip-arrow-height);\n height: var(--bs-tooltip-arrow-width);\n}\n.bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before {\n right: -1px;\n border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0;\n border-right-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:end:ignore */\n.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow {\n top: calc(-1 * var(--bs-tooltip-arrow-height));\n}\n.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before {\n bottom: -1px;\n border-width: 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height);\n border-bottom-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow {\n right: calc(-1 * var(--bs-tooltip-arrow-height));\n width: var(--bs-tooltip-arrow-height);\n height: var(--bs-tooltip-arrow-width);\n}\n.bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before {\n left: -1px;\n border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height);\n border-left-color: var(--bs-tooltip-bg);\n}\n\n/* rtl:end:ignore */\n.tooltip-inner {\n max-width: var(--bs-tooltip-max-width);\n padding: var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);\n color: var(--bs-tooltip-color);\n text-align: center;\n background-color: var(--bs-tooltip-bg);\n border-radius: var(--bs-tooltip-border-radius);\n}\n\n.popover {\n --bs-popover-zindex: 1070;\n --bs-popover-max-width: 276px;\n --bs-popover-font-size: 0.875rem;\n --bs-popover-bg: var(--bs-body-bg);\n --bs-popover-border-width: var(--bs-border-width);\n --bs-popover-border-color: var(--bs-border-color-translucent);\n --bs-popover-border-radius: var(--bs-border-radius-lg);\n --bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));\n --bs-popover-box-shadow: var(--bs-box-shadow);\n --bs-popover-header-padding-x: 1rem;\n --bs-popover-header-padding-y: 0.5rem;\n --bs-popover-header-font-size: 1rem;\n --bs-popover-header-color: inherit;\n --bs-popover-header-bg: var(--bs-secondary-bg);\n --bs-popover-body-padding-x: 1rem;\n --bs-popover-body-padding-y: 1rem;\n --bs-popover-body-color: var(--bs-body-color);\n --bs-popover-arrow-width: 1rem;\n --bs-popover-arrow-height: 0.5rem;\n --bs-popover-arrow-border: var(--bs-popover-border-color);\n z-index: var(--bs-popover-zindex);\n display: block;\n max-width: var(--bs-popover-max-width);\n font-family: var(--bs-font-sans-serif);\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n white-space: normal;\n word-spacing: normal;\n line-break: auto;\n font-size: var(--bs-popover-font-size);\n word-wrap: break-word;\n background-color: var(--bs-popover-bg);\n background-clip: padding-box;\n border: var(--bs-popover-border-width) solid var(--bs-popover-border-color);\n border-radius: var(--bs-popover-border-radius);\n}\n.popover .popover-arrow {\n display: block;\n width: var(--bs-popover-arrow-width);\n height: var(--bs-popover-arrow-height);\n}\n.popover .popover-arrow::before, .popover .popover-arrow::after {\n position: absolute;\n display: block;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n border-width: 0;\n}\n\n.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow {\n bottom: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n}\n.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {\n border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0;\n}\n.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before {\n bottom: 0;\n border-top-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {\n bottom: var(--bs-popover-border-width);\n border-top-color: var(--bs-popover-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow {\n left: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n width: var(--bs-popover-arrow-height);\n height: var(--bs-popover-arrow-width);\n}\n.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before, .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {\n border-width: calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0;\n}\n.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before {\n left: 0;\n border-right-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {\n left: var(--bs-popover-border-width);\n border-right-color: var(--bs-popover-bg);\n}\n\n/* rtl:end:ignore */\n.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow {\n top: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n}\n.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {\n border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height);\n}\n.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before {\n top: 0;\n border-bottom-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {\n top: var(--bs-popover-border-width);\n border-bottom-color: var(--bs-popover-bg);\n}\n.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: var(--bs-popover-arrow-width);\n margin-left: calc(-0.5 * var(--bs-popover-arrow-width));\n content: \"\";\n border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-header-bg);\n}\n\n/* rtl:begin:ignore */\n.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow {\n right: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));\n width: var(--bs-popover-arrow-height);\n height: var(--bs-popover-arrow-width);\n}\n.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before, .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {\n border-width: calc(var(--bs-popover-arrow-width) * 0.5) 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height);\n}\n.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before {\n right: 0;\n border-left-color: var(--bs-popover-arrow-border);\n}\n.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {\n right: var(--bs-popover-border-width);\n border-left-color: var(--bs-popover-bg);\n}\n\n/* rtl:end:ignore */\n.popover-header {\n padding: var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);\n margin-bottom: 0;\n font-size: var(--bs-popover-header-font-size);\n color: var(--bs-popover-header-color);\n background-color: var(--bs-popover-header-bg);\n border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-border-color);\n border-top-left-radius: var(--bs-popover-inner-border-radius);\n border-top-right-radius: var(--bs-popover-inner-border-radius);\n}\n.popover-header:empty {\n display: none;\n}\n\n.popover-body {\n padding: var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);\n color: var(--bs-popover-body-color);\n}\n\n.carousel {\n position: relative;\n}\n\n.carousel.pointer-event {\n touch-action: pan-y;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.carousel-item {\n position: relative;\n display: none;\n float: left;\n width: 100%;\n margin-right: -100%;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n transition: transform 0.6s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-item {\n transition: none;\n }\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n.carousel-item-next:not(.carousel-item-start),\n.active.carousel-item-end {\n transform: translateX(100%);\n}\n\n.carousel-item-prev:not(.carousel-item-end),\n.active.carousel-item-start {\n transform: translateX(-100%);\n}\n\n.carousel-fade .carousel-item {\n opacity: 0;\n transition-property: opacity;\n transform: none;\n}\n.carousel-fade .carousel-item.active,\n.carousel-fade .carousel-item-next.carousel-item-start,\n.carousel-fade .carousel-item-prev.carousel-item-end {\n z-index: 1;\n opacity: 1;\n}\n.carousel-fade .active.carousel-item-start,\n.carousel-fade .active.carousel-item-end {\n z-index: 0;\n opacity: 0;\n transition: opacity 0s 0.6s;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-fade .active.carousel-item-start,\n .carousel-fade .active.carousel-item-end {\n transition: none;\n }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 15%;\n padding: 0;\n color: #fff;\n text-align: center;\n background: none;\n border: 0;\n opacity: 0.5;\n transition: opacity 0.15s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-control-prev,\n .carousel-control-next {\n transition: none;\n }\n}\n.carousel-control-prev:hover, .carousel-control-prev:focus,\n.carousel-control-next:hover,\n.carousel-control-next:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n opacity: 0.9;\n}\n\n.carousel-control-prev {\n left: 0;\n}\n\n.carousel-control-next {\n right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n background-repeat: no-repeat;\n background-position: 50%;\n background-size: 100% 100%;\n}\n\n/* rtl:options: {\n \"autoRename\": true,\n \"stringMap\":[ {\n \"name\" : \"prev-next\",\n \"search\" : \"prev\",\n \"replace\" : \"next\"\n } ]\n} */\n.carousel-control-prev-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e\");\n}\n\n.carousel-control-next-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n}\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 2;\n display: flex;\n justify-content: center;\n padding: 0;\n margin-right: 15%;\n margin-bottom: 1rem;\n margin-left: 15%;\n}\n.carousel-indicators [data-bs-target] {\n box-sizing: content-box;\n flex: 0 1 auto;\n width: 30px;\n height: 3px;\n padding: 0;\n margin-right: 3px;\n margin-left: 3px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #fff;\n background-clip: padding-box;\n border: 0;\n border-top: 10px solid transparent;\n border-bottom: 10px solid transparent;\n opacity: 0.5;\n transition: opacity 0.6s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-indicators [data-bs-target] {\n transition: none;\n }\n}\n.carousel-indicators .active {\n opacity: 1;\n}\n\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 1.25rem;\n left: 15%;\n padding-top: 1.25rem;\n padding-bottom: 1.25rem;\n color: #fff;\n text-align: center;\n}\n\n.carousel-dark .carousel-control-prev-icon,\n.carousel-dark .carousel-control-next-icon {\n filter: invert(1) grayscale(100);\n}\n.carousel-dark .carousel-indicators [data-bs-target] {\n background-color: #000;\n}\n.carousel-dark .carousel-caption {\n color: #000;\n}\n\n[data-bs-theme=dark] .carousel .carousel-control-prev-icon,\n[data-bs-theme=dark] .carousel .carousel-control-next-icon, [data-bs-theme=dark].carousel .carousel-control-prev-icon,\n[data-bs-theme=dark].carousel .carousel-control-next-icon {\n filter: invert(1) grayscale(100);\n}\n[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target], [data-bs-theme=dark].carousel .carousel-indicators [data-bs-target] {\n background-color: #000;\n}\n[data-bs-theme=dark] .carousel .carousel-caption, [data-bs-theme=dark].carousel .carousel-caption {\n color: #000;\n}\n\n.spinner-grow,\n.spinner-border {\n display: inline-block;\n width: var(--bs-spinner-width);\n height: var(--bs-spinner-height);\n vertical-align: var(--bs-spinner-vertical-align);\n border-radius: 50%;\n animation: var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name);\n}\n\n@keyframes spinner-border {\n to {\n transform: rotate(360deg) /* rtl:ignore */;\n }\n}\n.spinner-border {\n --bs-spinner-width: 2rem;\n --bs-spinner-height: 2rem;\n --bs-spinner-vertical-align: -0.125em;\n --bs-spinner-border-width: 0.25em;\n --bs-spinner-animation-speed: 0.75s;\n --bs-spinner-animation-name: spinner-border;\n border: var(--bs-spinner-border-width) solid currentcolor;\n border-right-color: transparent;\n}\n\n.spinner-border-sm {\n --bs-spinner-width: 1rem;\n --bs-spinner-height: 1rem;\n --bs-spinner-border-width: 0.2em;\n}\n\n@keyframes spinner-grow {\n 0% {\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n transform: none;\n }\n}\n.spinner-grow {\n --bs-spinner-width: 2rem;\n --bs-spinner-height: 2rem;\n --bs-spinner-vertical-align: -0.125em;\n --bs-spinner-animation-speed: 0.75s;\n --bs-spinner-animation-name: spinner-grow;\n background-color: currentcolor;\n opacity: 0;\n}\n\n.spinner-grow-sm {\n --bs-spinner-width: 1rem;\n --bs-spinner-height: 1rem;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .spinner-border,\n .spinner-grow {\n --bs-spinner-animation-speed: 1.5s;\n }\n}\n.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm {\n --bs-offcanvas-zindex: 1045;\n --bs-offcanvas-width: 400px;\n --bs-offcanvas-height: 30vh;\n --bs-offcanvas-padding-x: 1rem;\n --bs-offcanvas-padding-y: 1rem;\n --bs-offcanvas-color: var(--bs-body-color);\n --bs-offcanvas-bg: var(--bs-body-bg);\n --bs-offcanvas-border-width: var(--bs-border-width);\n --bs-offcanvas-border-color: var(--bs-border-color-translucent);\n --bs-offcanvas-box-shadow: var(--bs-box-shadow-sm);\n --bs-offcanvas-transition: transform 0.3s ease-in-out;\n --bs-offcanvas-title-line-height: 1.5;\n}\n\n@media (max-width: 575.98px) {\n .offcanvas-sm {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 575.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-sm {\n transition: none;\n }\n}\n@media (max-width: 575.98px) {\n .offcanvas-sm.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-sm.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-sm.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-sm.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show {\n visibility: visible;\n }\n}\n@media (min-width: 576px) {\n .offcanvas-sm {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-sm .offcanvas-header {\n display: none;\n }\n .offcanvas-sm .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 767.98px) {\n .offcanvas-md {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-md {\n transition: none;\n }\n}\n@media (max-width: 767.98px) {\n .offcanvas-md.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-md.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-md.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-md.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show {\n visibility: visible;\n }\n}\n@media (min-width: 768px) {\n .offcanvas-md {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-md .offcanvas-header {\n display: none;\n }\n .offcanvas-md .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 991.98px) {\n .offcanvas-lg {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-lg {\n transition: none;\n }\n}\n@media (max-width: 991.98px) {\n .offcanvas-lg.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-lg.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-lg.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-lg.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show {\n visibility: visible;\n }\n}\n@media (min-width: 992px) {\n .offcanvas-lg {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-lg .offcanvas-header {\n display: none;\n }\n .offcanvas-lg .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 1199.98px) {\n .offcanvas-xl {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-xl {\n transition: none;\n }\n}\n@media (max-width: 1199.98px) {\n .offcanvas-xl.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-xl.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-xl.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-xl.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show {\n visibility: visible;\n }\n}\n@media (min-width: 1200px) {\n .offcanvas-xl {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-xl .offcanvas-header {\n display: none;\n }\n .offcanvas-xl .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n@media (max-width: 1399.98px) {\n .offcanvas-xxl {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n }\n}\n@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce) {\n .offcanvas-xxl {\n transition: none;\n }\n}\n@media (max-width: 1399.98px) {\n .offcanvas-xxl.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n }\n .offcanvas-xxl.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n }\n .offcanvas-xxl.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n }\n .offcanvas-xxl.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n }\n .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) {\n transform: none;\n }\n .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show {\n visibility: visible;\n }\n}\n@media (min-width: 1400px) {\n .offcanvas-xxl {\n --bs-offcanvas-height: auto;\n --bs-offcanvas-border-width: 0;\n background-color: transparent !important;\n }\n .offcanvas-xxl .offcanvas-header {\n display: none;\n }\n .offcanvas-xxl .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n background-color: transparent !important;\n }\n}\n\n.offcanvas {\n position: fixed;\n bottom: 0;\n z-index: var(--bs-offcanvas-zindex);\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: var(--bs-offcanvas-color);\n visibility: hidden;\n background-color: var(--bs-offcanvas-bg);\n background-clip: padding-box;\n outline: 0;\n transition: var(--bs-offcanvas-transition);\n}\n@media (prefers-reduced-motion: reduce) {\n .offcanvas {\n transition: none;\n }\n}\n.offcanvas.offcanvas-start {\n top: 0;\n left: 0;\n width: var(--bs-offcanvas-width);\n border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(-100%);\n}\n.offcanvas.offcanvas-end {\n top: 0;\n right: 0;\n width: var(--bs-offcanvas-width);\n border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateX(100%);\n}\n.offcanvas.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(-100%);\n}\n.offcanvas.offcanvas-bottom {\n right: 0;\n left: 0;\n height: var(--bs-offcanvas-height);\n max-height: 100%;\n border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);\n transform: translateY(100%);\n}\n.offcanvas.showing, .offcanvas.show:not(.hiding) {\n transform: none;\n}\n.offcanvas.showing, .offcanvas.hiding, .offcanvas.show {\n visibility: visible;\n}\n\n.offcanvas-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1040;\n width: 100vw;\n height: 100vh;\n background-color: #000;\n}\n.offcanvas-backdrop.fade {\n opacity: 0;\n}\n.offcanvas-backdrop.show {\n opacity: 0.5;\n}\n\n.offcanvas-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);\n}\n.offcanvas-header .btn-close {\n padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5);\n margin-top: calc(-0.5 * var(--bs-offcanvas-padding-y));\n margin-right: calc(-0.5 * var(--bs-offcanvas-padding-x));\n margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y));\n}\n\n.offcanvas-title {\n margin-bottom: 0;\n line-height: var(--bs-offcanvas-title-line-height);\n}\n\n.offcanvas-body {\n flex-grow: 1;\n padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);\n overflow-y: auto;\n}\n\n.placeholder {\n display: inline-block;\n min-height: 1em;\n vertical-align: middle;\n cursor: wait;\n background-color: currentcolor;\n opacity: 0.5;\n}\n.placeholder.btn::before {\n display: inline-block;\n content: \"\";\n}\n\n.placeholder-xs {\n min-height: 0.6em;\n}\n\n.placeholder-sm {\n min-height: 0.8em;\n}\n\n.placeholder-lg {\n min-height: 1.2em;\n}\n\n.placeholder-glow .placeholder {\n animation: placeholder-glow 2s ease-in-out infinite;\n}\n\n@keyframes placeholder-glow {\n 50% {\n opacity: 0.2;\n }\n}\n.placeholder-wave {\n -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\n mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\n -webkit-mask-size: 200% 100%;\n mask-size: 200% 100%;\n animation: placeholder-wave 2s linear infinite;\n}\n\n@keyframes placeholder-wave {\n 100% {\n -webkit-mask-position: -200% 0%;\n mask-position: -200% 0%;\n }\n}\n.clearfix::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.text-bg-primary {\n color: #fff !important;\n background-color: RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-secondary {\n color: #fff !important;\n background-color: RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-success {\n color: #fff !important;\n background-color: RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-info {\n color: #000 !important;\n background-color: RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-warning {\n color: #000 !important;\n background-color: RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-danger {\n color: #fff !important;\n background-color: RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-light {\n color: #000 !important;\n background-color: RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.text-bg-dark {\n color: #fff !important;\n background-color: RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important;\n}\n\n.link-primary {\n color: RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-primary:hover, .link-primary:focus {\n color: RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-secondary {\n color: RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-secondary:hover, .link-secondary:focus {\n color: RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-success {\n color: RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-success:hover, .link-success:focus {\n color: RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-info {\n color: RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-info:hover, .link-info:focus {\n color: RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-warning {\n color: RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-warning:hover, .link-warning:focus {\n color: RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-danger {\n color: RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-danger:hover, .link-danger:focus {\n color: RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-light {\n color: RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-light:hover, .link-light:focus {\n color: RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-dark {\n color: RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-dark:hover, .link-dark:focus {\n color: RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-body-emphasis {\n color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n.link-body-emphasis:hover, .link-body-emphasis:focus {\n color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;\n -webkit-text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important;\n text-decoration-color: RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important;\n}\n\n.focus-ring:focus {\n outline: 0;\n box-shadow: var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color);\n}\n\n.icon-link {\n display: inline-flex;\n gap: 0.375rem;\n align-items: center;\n -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));\n text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));\n text-underline-offset: 0.25em;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n}\n.icon-link > .bi {\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n fill: currentcolor;\n transition: 0.2s ease-in-out transform;\n}\n@media (prefers-reduced-motion: reduce) {\n .icon-link > .bi {\n transition: none;\n }\n}\n\n.icon-link-hover:hover > .bi, .icon-link-hover:focus-visible > .bi {\n transform: var(--bs-icon-link-transform, translate3d(0.25em, 0, 0));\n}\n\n.ratio {\n position: relative;\n width: 100%;\n}\n.ratio::before {\n display: block;\n padding-top: var(--bs-aspect-ratio);\n content: \"\";\n}\n.ratio > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n\n.ratio-1x1 {\n --bs-aspect-ratio: 100%;\n}\n\n.ratio-4x3 {\n --bs-aspect-ratio: 75%;\n}\n\n.ratio-16x9 {\n --bs-aspect-ratio: 56.25%;\n}\n\n.ratio-21x9 {\n --bs-aspect-ratio: 42.8571428571%;\n}\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1030;\n}\n\n.sticky-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n}\n\n.sticky-bottom {\n position: -webkit-sticky;\n position: sticky;\n bottom: 0;\n z-index: 1020;\n}\n\n@media (min-width: 576px) {\n .sticky-sm-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-sm-bottom {\n position: -webkit-sticky;\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 768px) {\n .sticky-md-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-md-bottom {\n position: -webkit-sticky;\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 992px) {\n .sticky-lg-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-lg-bottom {\n position: -webkit-sticky;\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 1200px) {\n .sticky-xl-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-xl-bottom {\n position: -webkit-sticky;\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 1400px) {\n .sticky-xxl-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n .sticky-xxl-bottom {\n position: -webkit-sticky;\n position: sticky;\n bottom: 0;\n z-index: 1020;\n }\n}\n.hstack {\n display: flex;\n flex-direction: row;\n align-items: center;\n align-self: stretch;\n}\n\n.vstack {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n align-self: stretch;\n}\n\n.visually-hidden,\n.visually-hidden-focusable:not(:focus):not(:focus-within) {\n width: 1px !important;\n height: 1px !important;\n padding: 0 !important;\n margin: -1px !important;\n overflow: hidden !important;\n clip: rect(0, 0, 0, 0) !important;\n white-space: nowrap !important;\n border: 0 !important;\n}\n.visually-hidden:not(caption),\n.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) {\n position: absolute !important;\n}\n\n.stretched-link::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1;\n content: \"\";\n}\n\n.text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.vr {\n display: inline-block;\n align-self: stretch;\n width: var(--bs-border-width);\n min-height: 1em;\n background-color: currentcolor;\n opacity: 0.25;\n}\n\n.align-baseline {\n vertical-align: baseline !important;\n}\n\n.align-top {\n vertical-align: top !important;\n}\n\n.align-middle {\n vertical-align: middle !important;\n}\n\n.align-bottom {\n vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n vertical-align: text-top !important;\n}\n\n.float-start {\n float: left !important;\n}\n\n.float-end {\n float: right !important;\n}\n\n.float-none {\n float: none !important;\n}\n\n.object-fit-contain {\n -o-object-fit: contain !important;\n object-fit: contain !important;\n}\n\n.object-fit-cover {\n -o-object-fit: cover !important;\n object-fit: cover !important;\n}\n\n.object-fit-fill {\n -o-object-fit: fill !important;\n object-fit: fill !important;\n}\n\n.object-fit-scale {\n -o-object-fit: scale-down !important;\n object-fit: scale-down !important;\n}\n\n.object-fit-none {\n -o-object-fit: none !important;\n object-fit: none !important;\n}\n\n.opacity-0 {\n opacity: 0 !important;\n}\n\n.opacity-25 {\n opacity: 0.25 !important;\n}\n\n.opacity-50 {\n opacity: 0.5 !important;\n}\n\n.opacity-75 {\n opacity: 0.75 !important;\n}\n\n.opacity-100 {\n opacity: 1 !important;\n}\n\n.overflow-auto {\n overflow: auto !important;\n}\n\n.overflow-hidden {\n overflow: hidden !important;\n}\n\n.overflow-visible {\n overflow: visible !important;\n}\n\n.overflow-scroll {\n overflow: scroll !important;\n}\n\n.overflow-x-auto {\n overflow-x: auto !important;\n}\n\n.overflow-x-hidden {\n overflow-x: hidden !important;\n}\n\n.overflow-x-visible {\n overflow-x: visible !important;\n}\n\n.overflow-x-scroll {\n overflow-x: scroll !important;\n}\n\n.overflow-y-auto {\n overflow-y: auto !important;\n}\n\n.overflow-y-hidden {\n overflow-y: hidden !important;\n}\n\n.overflow-y-visible {\n overflow-y: visible !important;\n}\n\n.overflow-y-scroll {\n overflow-y: scroll !important;\n}\n\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-grid {\n display: grid !important;\n}\n\n.d-inline-grid {\n display: inline-grid !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n.d-none {\n display: none !important;\n}\n\n.shadow {\n box-shadow: var(--bs-box-shadow) !important;\n}\n\n.shadow-sm {\n box-shadow: var(--bs-box-shadow-sm) !important;\n}\n\n.shadow-lg {\n box-shadow: var(--bs-box-shadow-lg) !important;\n}\n\n.shadow-none {\n box-shadow: none !important;\n}\n\n.focus-ring-primary {\n --bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-secondary {\n --bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-success {\n --bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-info {\n --bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-warning {\n --bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-danger {\n --bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-light {\n --bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity));\n}\n\n.focus-ring-dark {\n --bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity));\n}\n\n.position-static {\n position: static !important;\n}\n\n.position-relative {\n position: relative !important;\n}\n\n.position-absolute {\n position: absolute !important;\n}\n\n.position-fixed {\n position: fixed !important;\n}\n\n.position-sticky {\n position: -webkit-sticky !important;\n position: sticky !important;\n}\n\n.top-0 {\n top: 0 !important;\n}\n\n.top-50 {\n top: 50% !important;\n}\n\n.top-100 {\n top: 100% !important;\n}\n\n.bottom-0 {\n bottom: 0 !important;\n}\n\n.bottom-50 {\n bottom: 50% !important;\n}\n\n.bottom-100 {\n bottom: 100% !important;\n}\n\n.start-0 {\n left: 0 !important;\n}\n\n.start-50 {\n left: 50% !important;\n}\n\n.start-100 {\n left: 100% !important;\n}\n\n.end-0 {\n right: 0 !important;\n}\n\n.end-50 {\n right: 50% !important;\n}\n\n.end-100 {\n right: 100% !important;\n}\n\n.translate-middle {\n transform: translate(-50%, -50%) !important;\n}\n\n.translate-middle-x {\n transform: translateX(-50%) !important;\n}\n\n.translate-middle-y {\n transform: translateY(-50%) !important;\n}\n\n.border {\n border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-0 {\n border: 0 !important;\n}\n\n.border-top {\n border-top: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-top-0 {\n border-top: 0 !important;\n}\n\n.border-end {\n border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-end-0 {\n border-right: 0 !important;\n}\n\n.border-bottom {\n border-bottom: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-bottom-0 {\n border-bottom: 0 !important;\n}\n\n.border-start {\n border-left: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\n}\n\n.border-start-0 {\n border-left: 0 !important;\n}\n\n.border-primary {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-secondary {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-success {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-info {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-warning {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-danger {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-light {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-dark {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-black {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-white {\n --bs-border-opacity: 1;\n border-color: rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important;\n}\n\n.border-primary-subtle {\n border-color: var(--bs-primary-border-subtle) !important;\n}\n\n.border-secondary-subtle {\n border-color: var(--bs-secondary-border-subtle) !important;\n}\n\n.border-success-subtle {\n border-color: var(--bs-success-border-subtle) !important;\n}\n\n.border-info-subtle {\n border-color: var(--bs-info-border-subtle) !important;\n}\n\n.border-warning-subtle {\n border-color: var(--bs-warning-border-subtle) !important;\n}\n\n.border-danger-subtle {\n border-color: var(--bs-danger-border-subtle) !important;\n}\n\n.border-light-subtle {\n border-color: var(--bs-light-border-subtle) !important;\n}\n\n.border-dark-subtle {\n border-color: var(--bs-dark-border-subtle) !important;\n}\n\n.border-1 {\n border-width: 1px !important;\n}\n\n.border-2 {\n border-width: 2px !important;\n}\n\n.border-3 {\n border-width: 3px !important;\n}\n\n.border-4 {\n border-width: 4px !important;\n}\n\n.border-5 {\n border-width: 5px !important;\n}\n\n.border-opacity-10 {\n --bs-border-opacity: 0.1;\n}\n\n.border-opacity-25 {\n --bs-border-opacity: 0.25;\n}\n\n.border-opacity-50 {\n --bs-border-opacity: 0.5;\n}\n\n.border-opacity-75 {\n --bs-border-opacity: 0.75;\n}\n\n.border-opacity-100 {\n --bs-border-opacity: 1;\n}\n\n.w-25 {\n width: 25% !important;\n}\n\n.w-50 {\n width: 50% !important;\n}\n\n.w-75 {\n width: 75% !important;\n}\n\n.w-100 {\n width: 100% !important;\n}\n\n.w-auto {\n width: auto !important;\n}\n\n.mw-100 {\n max-width: 100% !important;\n}\n\n.vw-100 {\n width: 100vw !important;\n}\n\n.min-vw-100 {\n min-width: 100vw !important;\n}\n\n.h-25 {\n height: 25% !important;\n}\n\n.h-50 {\n height: 50% !important;\n}\n\n.h-75 {\n height: 75% !important;\n}\n\n.h-100 {\n height: 100% !important;\n}\n\n.h-auto {\n height: auto !important;\n}\n\n.mh-100 {\n max-height: 100% !important;\n}\n\n.vh-100 {\n height: 100vh !important;\n}\n\n.min-vh-100 {\n min-height: 100vh !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.justify-content-evenly {\n justify-content: space-evenly !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n.order-first {\n order: -1 !important;\n}\n\n.order-0 {\n order: 0 !important;\n}\n\n.order-1 {\n order: 1 !important;\n}\n\n.order-2 {\n order: 2 !important;\n}\n\n.order-3 {\n order: 3 !important;\n}\n\n.order-4 {\n order: 4 !important;\n}\n\n.order-5 {\n order: 5 !important;\n}\n\n.order-last {\n order: 6 !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.me-0 {\n margin-right: 0 !important;\n}\n\n.me-1 {\n margin-right: 0.25rem !important;\n}\n\n.me-2 {\n margin-right: 0.5rem !important;\n}\n\n.me-3 {\n margin-right: 1rem !important;\n}\n\n.me-4 {\n margin-right: 1.5rem !important;\n}\n\n.me-5 {\n margin-right: 3rem !important;\n}\n\n.me-auto {\n margin-right: auto !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ms-0 {\n margin-left: 0 !important;\n}\n\n.ms-1 {\n margin-left: 0.25rem !important;\n}\n\n.ms-2 {\n margin-left: 0.5rem !important;\n}\n\n.ms-3 {\n margin-left: 1rem !important;\n}\n\n.ms-4 {\n margin-left: 1.5rem !important;\n}\n\n.ms-5 {\n margin-left: 3rem !important;\n}\n\n.ms-auto {\n margin-left: auto !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pe-0 {\n padding-right: 0 !important;\n}\n\n.pe-1 {\n padding-right: 0.25rem !important;\n}\n\n.pe-2 {\n padding-right: 0.5rem !important;\n}\n\n.pe-3 {\n padding-right: 1rem !important;\n}\n\n.pe-4 {\n padding-right: 1.5rem !important;\n}\n\n.pe-5 {\n padding-right: 3rem !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.ps-0 {\n padding-left: 0 !important;\n}\n\n.ps-1 {\n padding-left: 0.25rem !important;\n}\n\n.ps-2 {\n padding-left: 0.5rem !important;\n}\n\n.ps-3 {\n padding-left: 1rem !important;\n}\n\n.ps-4 {\n padding-left: 1.5rem !important;\n}\n\n.ps-5 {\n padding-left: 3rem !important;\n}\n\n.gap-0 {\n gap: 0 !important;\n}\n\n.gap-1 {\n gap: 0.25rem !important;\n}\n\n.gap-2 {\n gap: 0.5rem !important;\n}\n\n.gap-3 {\n gap: 1rem !important;\n}\n\n.gap-4 {\n gap: 1.5rem !important;\n}\n\n.gap-5 {\n gap: 3rem !important;\n}\n\n.row-gap-0 {\n row-gap: 0 !important;\n}\n\n.row-gap-1 {\n row-gap: 0.25rem !important;\n}\n\n.row-gap-2 {\n row-gap: 0.5rem !important;\n}\n\n.row-gap-3 {\n row-gap: 1rem !important;\n}\n\n.row-gap-4 {\n row-gap: 1.5rem !important;\n}\n\n.row-gap-5 {\n row-gap: 3rem !important;\n}\n\n.column-gap-0 {\n -moz-column-gap: 0 !important;\n column-gap: 0 !important;\n}\n\n.column-gap-1 {\n -moz-column-gap: 0.25rem !important;\n column-gap: 0.25rem !important;\n}\n\n.column-gap-2 {\n -moz-column-gap: 0.5rem !important;\n column-gap: 0.5rem !important;\n}\n\n.column-gap-3 {\n -moz-column-gap: 1rem !important;\n column-gap: 1rem !important;\n}\n\n.column-gap-4 {\n -moz-column-gap: 1.5rem !important;\n column-gap: 1.5rem !important;\n}\n\n.column-gap-5 {\n -moz-column-gap: 3rem !important;\n column-gap: 3rem !important;\n}\n\n.font-monospace {\n font-family: var(--bs-font-monospace) !important;\n}\n\n.fs-1 {\n font-size: calc(1.375rem + 1.5vw) !important;\n}\n\n.fs-2 {\n font-size: calc(1.325rem + 0.9vw) !important;\n}\n\n.fs-3 {\n font-size: calc(1.3rem + 0.6vw) !important;\n}\n\n.fs-4 {\n font-size: calc(1.275rem + 0.3vw) !important;\n}\n\n.fs-5 {\n font-size: 1.25rem !important;\n}\n\n.fs-6 {\n font-size: 1rem !important;\n}\n\n.fst-italic {\n font-style: italic !important;\n}\n\n.fst-normal {\n font-style: normal !important;\n}\n\n.fw-lighter {\n font-weight: lighter !important;\n}\n\n.fw-light {\n font-weight: 300 !important;\n}\n\n.fw-normal {\n font-weight: 400 !important;\n}\n\n.fw-medium {\n font-weight: 500 !important;\n}\n\n.fw-semibold {\n font-weight: 600 !important;\n}\n\n.fw-bold {\n font-weight: 700 !important;\n}\n\n.fw-bolder {\n font-weight: bolder !important;\n}\n\n.lh-1 {\n line-height: 1 !important;\n}\n\n.lh-sm {\n line-height: 1.25 !important;\n}\n\n.lh-base {\n line-height: 1.5 !important;\n}\n\n.lh-lg {\n line-height: 2 !important;\n}\n\n.text-start {\n text-align: left !important;\n}\n\n.text-end {\n text-align: right !important;\n}\n\n.text-center {\n text-align: center !important;\n}\n\n.text-decoration-none {\n text-decoration: none !important;\n}\n\n.text-decoration-underline {\n text-decoration: underline !important;\n}\n\n.text-decoration-line-through {\n text-decoration: line-through !important;\n}\n\n.text-lowercase {\n text-transform: lowercase !important;\n}\n\n.text-uppercase {\n text-transform: uppercase !important;\n}\n\n.text-capitalize {\n text-transform: capitalize !important;\n}\n\n.text-wrap {\n white-space: normal !important;\n}\n\n.text-nowrap {\n white-space: nowrap !important;\n}\n\n/* rtl:begin:remove */\n.text-break {\n word-wrap: break-word !important;\n word-break: break-word !important;\n}\n\n/* rtl:end:remove */\n.text-primary {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-secondary {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-success {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-info {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-warning {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-danger {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-light {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-dark {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-black {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-white {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-body {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-muted {\n --bs-text-opacity: 1;\n color: var(--bs-secondary-color) !important;\n}\n\n.text-black-50 {\n --bs-text-opacity: 1;\n color: rgba(0, 0, 0, 0.5) !important;\n}\n\n.text-white-50 {\n --bs-text-opacity: 1;\n color: rgba(255, 255, 255, 0.5) !important;\n}\n\n.text-body-secondary {\n --bs-text-opacity: 1;\n color: var(--bs-secondary-color) !important;\n}\n\n.text-body-tertiary {\n --bs-text-opacity: 1;\n color: var(--bs-tertiary-color) !important;\n}\n\n.text-body-emphasis {\n --bs-text-opacity: 1;\n color: var(--bs-emphasis-color) !important;\n}\n\n.text-reset {\n --bs-text-opacity: 1;\n color: inherit !important;\n}\n\n.text-opacity-25 {\n --bs-text-opacity: 0.25;\n}\n\n.text-opacity-50 {\n --bs-text-opacity: 0.5;\n}\n\n.text-opacity-75 {\n --bs-text-opacity: 0.75;\n}\n\n.text-opacity-100 {\n --bs-text-opacity: 1;\n}\n\n.text-primary-emphasis {\n color: var(--bs-primary-text-emphasis) !important;\n}\n\n.text-secondary-emphasis {\n color: var(--bs-secondary-text-emphasis) !important;\n}\n\n.text-success-emphasis {\n color: var(--bs-success-text-emphasis) !important;\n}\n\n.text-info-emphasis {\n color: var(--bs-info-text-emphasis) !important;\n}\n\n.text-warning-emphasis {\n color: var(--bs-warning-text-emphasis) !important;\n}\n\n.text-danger-emphasis {\n color: var(--bs-danger-text-emphasis) !important;\n}\n\n.text-light-emphasis {\n color: var(--bs-light-text-emphasis) !important;\n}\n\n.text-dark-emphasis {\n color: var(--bs-dark-text-emphasis) !important;\n}\n\n.link-opacity-10 {\n --bs-link-opacity: 0.1;\n}\n\n.link-opacity-10-hover:hover {\n --bs-link-opacity: 0.1;\n}\n\n.link-opacity-25 {\n --bs-link-opacity: 0.25;\n}\n\n.link-opacity-25-hover:hover {\n --bs-link-opacity: 0.25;\n}\n\n.link-opacity-50 {\n --bs-link-opacity: 0.5;\n}\n\n.link-opacity-50-hover:hover {\n --bs-link-opacity: 0.5;\n}\n\n.link-opacity-75 {\n --bs-link-opacity: 0.75;\n}\n\n.link-opacity-75-hover:hover {\n --bs-link-opacity: 0.75;\n}\n\n.link-opacity-100 {\n --bs-link-opacity: 1;\n}\n\n.link-opacity-100-hover:hover {\n --bs-link-opacity: 1;\n}\n\n.link-offset-1 {\n text-underline-offset: 0.125em !important;\n}\n\n.link-offset-1-hover:hover {\n text-underline-offset: 0.125em !important;\n}\n\n.link-offset-2 {\n text-underline-offset: 0.25em !important;\n}\n\n.link-offset-2-hover:hover {\n text-underline-offset: 0.25em !important;\n}\n\n.link-offset-3 {\n text-underline-offset: 0.375em !important;\n}\n\n.link-offset-3-hover:hover {\n text-underline-offset: 0.375em !important;\n}\n\n.link-underline-primary {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-secondary {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-success {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-info {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-warning {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-danger {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-light {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline-dark {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important;\n text-decoration-color: rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important;\n}\n\n.link-underline {\n --bs-link-underline-opacity: 1;\n -webkit-text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important;\n text-decoration-color: rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important;\n}\n\n.link-underline-opacity-0 {\n --bs-link-underline-opacity: 0;\n}\n\n.link-underline-opacity-0-hover:hover {\n --bs-link-underline-opacity: 0;\n}\n\n.link-underline-opacity-10 {\n --bs-link-underline-opacity: 0.1;\n}\n\n.link-underline-opacity-10-hover:hover {\n --bs-link-underline-opacity: 0.1;\n}\n\n.link-underline-opacity-25 {\n --bs-link-underline-opacity: 0.25;\n}\n\n.link-underline-opacity-25-hover:hover {\n --bs-link-underline-opacity: 0.25;\n}\n\n.link-underline-opacity-50 {\n --bs-link-underline-opacity: 0.5;\n}\n\n.link-underline-opacity-50-hover:hover {\n --bs-link-underline-opacity: 0.5;\n}\n\n.link-underline-opacity-75 {\n --bs-link-underline-opacity: 0.75;\n}\n\n.link-underline-opacity-75-hover:hover {\n --bs-link-underline-opacity: 0.75;\n}\n\n.link-underline-opacity-100 {\n --bs-link-underline-opacity: 1;\n}\n\n.link-underline-opacity-100-hover:hover {\n --bs-link-underline-opacity: 1;\n}\n\n.bg-primary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-secondary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-success {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-info {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-warning {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-danger {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-light {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-dark {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-black {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-white {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-body {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-transparent {\n --bs-bg-opacity: 1;\n background-color: transparent !important;\n}\n\n.bg-body-secondary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-body-tertiary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-opacity-10 {\n --bs-bg-opacity: 0.1;\n}\n\n.bg-opacity-25 {\n --bs-bg-opacity: 0.25;\n}\n\n.bg-opacity-50 {\n --bs-bg-opacity: 0.5;\n}\n\n.bg-opacity-75 {\n --bs-bg-opacity: 0.75;\n}\n\n.bg-opacity-100 {\n --bs-bg-opacity: 1;\n}\n\n.bg-primary-subtle {\n background-color: var(--bs-primary-bg-subtle) !important;\n}\n\n.bg-secondary-subtle {\n background-color: var(--bs-secondary-bg-subtle) !important;\n}\n\n.bg-success-subtle {\n background-color: var(--bs-success-bg-subtle) !important;\n}\n\n.bg-info-subtle {\n background-color: var(--bs-info-bg-subtle) !important;\n}\n\n.bg-warning-subtle {\n background-color: var(--bs-warning-bg-subtle) !important;\n}\n\n.bg-danger-subtle {\n background-color: var(--bs-danger-bg-subtle) !important;\n}\n\n.bg-light-subtle {\n background-color: var(--bs-light-bg-subtle) !important;\n}\n\n.bg-dark-subtle {\n background-color: var(--bs-dark-bg-subtle) !important;\n}\n\n.bg-gradient {\n background-image: var(--bs-gradient) !important;\n}\n\n.user-select-all {\n -webkit-user-select: all !important;\n -moz-user-select: all !important;\n user-select: all !important;\n}\n\n.user-select-auto {\n -webkit-user-select: auto !important;\n -moz-user-select: auto !important;\n user-select: auto !important;\n}\n\n.user-select-none {\n -webkit-user-select: none !important;\n -moz-user-select: none !important;\n user-select: none !important;\n}\n\n.pe-none {\n pointer-events: none !important;\n}\n\n.pe-auto {\n pointer-events: auto !important;\n}\n\n.rounded {\n border-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-0 {\n border-radius: 0 !important;\n}\n\n.rounded-1 {\n border-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-2 {\n border-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-3 {\n border-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-4 {\n border-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-5 {\n border-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-circle {\n border-radius: 50% !important;\n}\n\n.rounded-pill {\n border-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-top {\n border-top-left-radius: var(--bs-border-radius) !important;\n border-top-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-top-0 {\n border-top-left-radius: 0 !important;\n border-top-right-radius: 0 !important;\n}\n\n.rounded-top-1 {\n border-top-left-radius: var(--bs-border-radius-sm) !important;\n border-top-right-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-top-2 {\n border-top-left-radius: var(--bs-border-radius) !important;\n border-top-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-top-3 {\n border-top-left-radius: var(--bs-border-radius-lg) !important;\n border-top-right-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-top-4 {\n border-top-left-radius: var(--bs-border-radius-xl) !important;\n border-top-right-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-top-5 {\n border-top-left-radius: var(--bs-border-radius-xxl) !important;\n border-top-right-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-top-circle {\n border-top-left-radius: 50% !important;\n border-top-right-radius: 50% !important;\n}\n\n.rounded-top-pill {\n border-top-left-radius: var(--bs-border-radius-pill) !important;\n border-top-right-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-end {\n border-top-right-radius: var(--bs-border-radius) !important;\n border-bottom-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-end-0 {\n border-top-right-radius: 0 !important;\n border-bottom-right-radius: 0 !important;\n}\n\n.rounded-end-1 {\n border-top-right-radius: var(--bs-border-radius-sm) !important;\n border-bottom-right-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-end-2 {\n border-top-right-radius: var(--bs-border-radius) !important;\n border-bottom-right-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-end-3 {\n border-top-right-radius: var(--bs-border-radius-lg) !important;\n border-bottom-right-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-end-4 {\n border-top-right-radius: var(--bs-border-radius-xl) !important;\n border-bottom-right-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-end-5 {\n border-top-right-radius: var(--bs-border-radius-xxl) !important;\n border-bottom-right-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-end-circle {\n border-top-right-radius: 50% !important;\n border-bottom-right-radius: 50% !important;\n}\n\n.rounded-end-pill {\n border-top-right-radius: var(--bs-border-radius-pill) !important;\n border-bottom-right-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-bottom {\n border-bottom-right-radius: var(--bs-border-radius) !important;\n border-bottom-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-bottom-0 {\n border-bottom-right-radius: 0 !important;\n border-bottom-left-radius: 0 !important;\n}\n\n.rounded-bottom-1 {\n border-bottom-right-radius: var(--bs-border-radius-sm) !important;\n border-bottom-left-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-bottom-2 {\n border-bottom-right-radius: var(--bs-border-radius) !important;\n border-bottom-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-bottom-3 {\n border-bottom-right-radius: var(--bs-border-radius-lg) !important;\n border-bottom-left-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-bottom-4 {\n border-bottom-right-radius: var(--bs-border-radius-xl) !important;\n border-bottom-left-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-bottom-5 {\n border-bottom-right-radius: var(--bs-border-radius-xxl) !important;\n border-bottom-left-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-bottom-circle {\n border-bottom-right-radius: 50% !important;\n border-bottom-left-radius: 50% !important;\n}\n\n.rounded-bottom-pill {\n border-bottom-right-radius: var(--bs-border-radius-pill) !important;\n border-bottom-left-radius: var(--bs-border-radius-pill) !important;\n}\n\n.rounded-start {\n border-bottom-left-radius: var(--bs-border-radius) !important;\n border-top-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-start-0 {\n border-bottom-left-radius: 0 !important;\n border-top-left-radius: 0 !important;\n}\n\n.rounded-start-1 {\n border-bottom-left-radius: var(--bs-border-radius-sm) !important;\n border-top-left-radius: var(--bs-border-radius-sm) !important;\n}\n\n.rounded-start-2 {\n border-bottom-left-radius: var(--bs-border-radius) !important;\n border-top-left-radius: var(--bs-border-radius) !important;\n}\n\n.rounded-start-3 {\n border-bottom-left-radius: var(--bs-border-radius-lg) !important;\n border-top-left-radius: var(--bs-border-radius-lg) !important;\n}\n\n.rounded-start-4 {\n border-bottom-left-radius: var(--bs-border-radius-xl) !important;\n border-top-left-radius: var(--bs-border-radius-xl) !important;\n}\n\n.rounded-start-5 {\n border-bottom-left-radius: var(--bs-border-radius-xxl) !important;\n border-top-left-radius: var(--bs-border-radius-xxl) !important;\n}\n\n.rounded-start-circle {\n border-bottom-left-radius: 50% !important;\n border-top-left-radius: 50% !important;\n}\n\n.rounded-start-pill {\n border-bottom-left-radius: var(--bs-border-radius-pill) !important;\n border-top-left-radius: var(--bs-border-radius-pill) !important;\n}\n\n.visible {\n visibility: visible !important;\n}\n\n.invisible {\n visibility: hidden !important;\n}\n\n.z-n1 {\n z-index: -1 !important;\n}\n\n.z-0 {\n z-index: 0 !important;\n}\n\n.z-1 {\n z-index: 1 !important;\n}\n\n.z-2 {\n z-index: 2 !important;\n}\n\n.z-3 {\n z-index: 3 !important;\n}\n\n@media (min-width: 576px) {\n .float-sm-start {\n float: left !important;\n }\n .float-sm-end {\n float: right !important;\n }\n .float-sm-none {\n float: none !important;\n }\n .object-fit-sm-contain {\n -o-object-fit: contain !important;\n object-fit: contain !important;\n }\n .object-fit-sm-cover {\n -o-object-fit: cover !important;\n object-fit: cover !important;\n }\n .object-fit-sm-fill {\n -o-object-fit: fill !important;\n object-fit: fill !important;\n }\n .object-fit-sm-scale {\n -o-object-fit: scale-down !important;\n object-fit: scale-down !important;\n }\n .object-fit-sm-none {\n -o-object-fit: none !important;\n object-fit: none !important;\n }\n .d-sm-inline {\n display: inline !important;\n }\n .d-sm-inline-block {\n display: inline-block !important;\n }\n .d-sm-block {\n display: block !important;\n }\n .d-sm-grid {\n display: grid !important;\n }\n .d-sm-inline-grid {\n display: inline-grid !important;\n }\n .d-sm-table {\n display: table !important;\n }\n .d-sm-table-row {\n display: table-row !important;\n }\n .d-sm-table-cell {\n display: table-cell !important;\n }\n .d-sm-flex {\n display: flex !important;\n }\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n .d-sm-none {\n display: none !important;\n }\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n .flex-sm-row {\n flex-direction: row !important;\n }\n .flex-sm-column {\n flex-direction: column !important;\n }\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n .justify-content-sm-center {\n justify-content: center !important;\n }\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n .justify-content-sm-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n .align-items-sm-center {\n align-items: center !important;\n }\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n .align-content-sm-center {\n align-content: center !important;\n }\n .align-content-sm-between {\n align-content: space-between !important;\n }\n .align-content-sm-around {\n align-content: space-around !important;\n }\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n .align-self-sm-auto {\n align-self: auto !important;\n }\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n .align-self-sm-center {\n align-self: center !important;\n }\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n .order-sm-first {\n order: -1 !important;\n }\n .order-sm-0 {\n order: 0 !important;\n }\n .order-sm-1 {\n order: 1 !important;\n }\n .order-sm-2 {\n order: 2 !important;\n }\n .order-sm-3 {\n order: 3 !important;\n }\n .order-sm-4 {\n order: 4 !important;\n }\n .order-sm-5 {\n order: 5 !important;\n }\n .order-sm-last {\n order: 6 !important;\n }\n .m-sm-0 {\n margin: 0 !important;\n }\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n .m-sm-3 {\n margin: 1rem !important;\n }\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n .m-sm-5 {\n margin: 3rem !important;\n }\n .m-sm-auto {\n margin: auto !important;\n }\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n .mt-sm-auto {\n margin-top: auto !important;\n }\n .me-sm-0 {\n margin-right: 0 !important;\n }\n .me-sm-1 {\n margin-right: 0.25rem !important;\n }\n .me-sm-2 {\n margin-right: 0.5rem !important;\n }\n .me-sm-3 {\n margin-right: 1rem !important;\n }\n .me-sm-4 {\n margin-right: 1.5rem !important;\n }\n .me-sm-5 {\n margin-right: 3rem !important;\n }\n .me-sm-auto {\n margin-right: auto !important;\n }\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n .ms-sm-0 {\n margin-left: 0 !important;\n }\n .ms-sm-1 {\n margin-left: 0.25rem !important;\n }\n .ms-sm-2 {\n margin-left: 0.5rem !important;\n }\n .ms-sm-3 {\n margin-left: 1rem !important;\n }\n .ms-sm-4 {\n margin-left: 1.5rem !important;\n }\n .ms-sm-5 {\n margin-left: 3rem !important;\n }\n .ms-sm-auto {\n margin-left: auto !important;\n }\n .p-sm-0 {\n padding: 0 !important;\n }\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n .p-sm-3 {\n padding: 1rem !important;\n }\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n .p-sm-5 {\n padding: 3rem !important;\n }\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n .pe-sm-0 {\n padding-right: 0 !important;\n }\n .pe-sm-1 {\n padding-right: 0.25rem !important;\n }\n .pe-sm-2 {\n padding-right: 0.5rem !important;\n }\n .pe-sm-3 {\n padding-right: 1rem !important;\n }\n .pe-sm-4 {\n padding-right: 1.5rem !important;\n }\n .pe-sm-5 {\n padding-right: 3rem !important;\n }\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n .ps-sm-0 {\n padding-left: 0 !important;\n }\n .ps-sm-1 {\n padding-left: 0.25rem !important;\n }\n .ps-sm-2 {\n padding-left: 0.5rem !important;\n }\n .ps-sm-3 {\n padding-left: 1rem !important;\n }\n .ps-sm-4 {\n padding-left: 1.5rem !important;\n }\n .ps-sm-5 {\n padding-left: 3rem !important;\n }\n .gap-sm-0 {\n gap: 0 !important;\n }\n .gap-sm-1 {\n gap: 0.25rem !important;\n }\n .gap-sm-2 {\n gap: 0.5rem !important;\n }\n .gap-sm-3 {\n gap: 1rem !important;\n }\n .gap-sm-4 {\n gap: 1.5rem !important;\n }\n .gap-sm-5 {\n gap: 3rem !important;\n }\n .row-gap-sm-0 {\n row-gap: 0 !important;\n }\n .row-gap-sm-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-sm-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-sm-3 {\n row-gap: 1rem !important;\n }\n .row-gap-sm-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-sm-5 {\n row-gap: 3rem !important;\n }\n .column-gap-sm-0 {\n -moz-column-gap: 0 !important;\n column-gap: 0 !important;\n }\n .column-gap-sm-1 {\n -moz-column-gap: 0.25rem !important;\n column-gap: 0.25rem !important;\n }\n .column-gap-sm-2 {\n -moz-column-gap: 0.5rem !important;\n column-gap: 0.5rem !important;\n }\n .column-gap-sm-3 {\n -moz-column-gap: 1rem !important;\n column-gap: 1rem !important;\n }\n .column-gap-sm-4 {\n -moz-column-gap: 1.5rem !important;\n column-gap: 1.5rem !important;\n }\n .column-gap-sm-5 {\n -moz-column-gap: 3rem !important;\n column-gap: 3rem !important;\n }\n .text-sm-start {\n text-align: left !important;\n }\n .text-sm-end {\n text-align: right !important;\n }\n .text-sm-center {\n text-align: center !important;\n }\n}\n@media (min-width: 768px) {\n .float-md-start {\n float: left !important;\n }\n .float-md-end {\n float: right !important;\n }\n .float-md-none {\n float: none !important;\n }\n .object-fit-md-contain {\n -o-object-fit: contain !important;\n object-fit: contain !important;\n }\n .object-fit-md-cover {\n -o-object-fit: cover !important;\n object-fit: cover !important;\n }\n .object-fit-md-fill {\n -o-object-fit: fill !important;\n object-fit: fill !important;\n }\n .object-fit-md-scale {\n -o-object-fit: scale-down !important;\n object-fit: scale-down !important;\n }\n .object-fit-md-none {\n -o-object-fit: none !important;\n object-fit: none !important;\n }\n .d-md-inline {\n display: inline !important;\n }\n .d-md-inline-block {\n display: inline-block !important;\n }\n .d-md-block {\n display: block !important;\n }\n .d-md-grid {\n display: grid !important;\n }\n .d-md-inline-grid {\n display: inline-grid !important;\n }\n .d-md-table {\n display: table !important;\n }\n .d-md-table-row {\n display: table-row !important;\n }\n .d-md-table-cell {\n display: table-cell !important;\n }\n .d-md-flex {\n display: flex !important;\n }\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n .d-md-none {\n display: none !important;\n }\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n .flex-md-row {\n flex-direction: row !important;\n }\n .flex-md-column {\n flex-direction: column !important;\n }\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n .justify-content-md-center {\n justify-content: center !important;\n }\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n .justify-content-md-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-md-start {\n align-items: flex-start !important;\n }\n .align-items-md-end {\n align-items: flex-end !important;\n }\n .align-items-md-center {\n align-items: center !important;\n }\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n .align-content-md-start {\n align-content: flex-start !important;\n }\n .align-content-md-end {\n align-content: flex-end !important;\n }\n .align-content-md-center {\n align-content: center !important;\n }\n .align-content-md-between {\n align-content: space-between !important;\n }\n .align-content-md-around {\n align-content: space-around !important;\n }\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n .align-self-md-auto {\n align-self: auto !important;\n }\n .align-self-md-start {\n align-self: flex-start !important;\n }\n .align-self-md-end {\n align-self: flex-end !important;\n }\n .align-self-md-center {\n align-self: center !important;\n }\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n .order-md-first {\n order: -1 !important;\n }\n .order-md-0 {\n order: 0 !important;\n }\n .order-md-1 {\n order: 1 !important;\n }\n .order-md-2 {\n order: 2 !important;\n }\n .order-md-3 {\n order: 3 !important;\n }\n .order-md-4 {\n order: 4 !important;\n }\n .order-md-5 {\n order: 5 !important;\n }\n .order-md-last {\n order: 6 !important;\n }\n .m-md-0 {\n margin: 0 !important;\n }\n .m-md-1 {\n margin: 0.25rem !important;\n }\n .m-md-2 {\n margin: 0.5rem !important;\n }\n .m-md-3 {\n margin: 1rem !important;\n }\n .m-md-4 {\n margin: 1.5rem !important;\n }\n .m-md-5 {\n margin: 3rem !important;\n }\n .m-md-auto {\n margin: auto !important;\n }\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-md-0 {\n margin-top: 0 !important;\n }\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n .mt-md-auto {\n margin-top: auto !important;\n }\n .me-md-0 {\n margin-right: 0 !important;\n }\n .me-md-1 {\n margin-right: 0.25rem !important;\n }\n .me-md-2 {\n margin-right: 0.5rem !important;\n }\n .me-md-3 {\n margin-right: 1rem !important;\n }\n .me-md-4 {\n margin-right: 1.5rem !important;\n }\n .me-md-5 {\n margin-right: 3rem !important;\n }\n .me-md-auto {\n margin-right: auto !important;\n }\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n .ms-md-0 {\n margin-left: 0 !important;\n }\n .ms-md-1 {\n margin-left: 0.25rem !important;\n }\n .ms-md-2 {\n margin-left: 0.5rem !important;\n }\n .ms-md-3 {\n margin-left: 1rem !important;\n }\n .ms-md-4 {\n margin-left: 1.5rem !important;\n }\n .ms-md-5 {\n margin-left: 3rem !important;\n }\n .ms-md-auto {\n margin-left: auto !important;\n }\n .p-md-0 {\n padding: 0 !important;\n }\n .p-md-1 {\n padding: 0.25rem !important;\n }\n .p-md-2 {\n padding: 0.5rem !important;\n }\n .p-md-3 {\n padding: 1rem !important;\n }\n .p-md-4 {\n padding: 1.5rem !important;\n }\n .p-md-5 {\n padding: 3rem !important;\n }\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-md-0 {\n padding-top: 0 !important;\n }\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n .pe-md-0 {\n padding-right: 0 !important;\n }\n .pe-md-1 {\n padding-right: 0.25rem !important;\n }\n .pe-md-2 {\n padding-right: 0.5rem !important;\n }\n .pe-md-3 {\n padding-right: 1rem !important;\n }\n .pe-md-4 {\n padding-right: 1.5rem !important;\n }\n .pe-md-5 {\n padding-right: 3rem !important;\n }\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n .ps-md-0 {\n padding-left: 0 !important;\n }\n .ps-md-1 {\n padding-left: 0.25rem !important;\n }\n .ps-md-2 {\n padding-left: 0.5rem !important;\n }\n .ps-md-3 {\n padding-left: 1rem !important;\n }\n .ps-md-4 {\n padding-left: 1.5rem !important;\n }\n .ps-md-5 {\n padding-left: 3rem !important;\n }\n .gap-md-0 {\n gap: 0 !important;\n }\n .gap-md-1 {\n gap: 0.25rem !important;\n }\n .gap-md-2 {\n gap: 0.5rem !important;\n }\n .gap-md-3 {\n gap: 1rem !important;\n }\n .gap-md-4 {\n gap: 1.5rem !important;\n }\n .gap-md-5 {\n gap: 3rem !important;\n }\n .row-gap-md-0 {\n row-gap: 0 !important;\n }\n .row-gap-md-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-md-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-md-3 {\n row-gap: 1rem !important;\n }\n .row-gap-md-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-md-5 {\n row-gap: 3rem !important;\n }\n .column-gap-md-0 {\n -moz-column-gap: 0 !important;\n column-gap: 0 !important;\n }\n .column-gap-md-1 {\n -moz-column-gap: 0.25rem !important;\n column-gap: 0.25rem !important;\n }\n .column-gap-md-2 {\n -moz-column-gap: 0.5rem !important;\n column-gap: 0.5rem !important;\n }\n .column-gap-md-3 {\n -moz-column-gap: 1rem !important;\n column-gap: 1rem !important;\n }\n .column-gap-md-4 {\n -moz-column-gap: 1.5rem !important;\n column-gap: 1.5rem !important;\n }\n .column-gap-md-5 {\n -moz-column-gap: 3rem !important;\n column-gap: 3rem !important;\n }\n .text-md-start {\n text-align: left !important;\n }\n .text-md-end {\n text-align: right !important;\n }\n .text-md-center {\n text-align: center !important;\n }\n}\n@media (min-width: 992px) {\n .float-lg-start {\n float: left !important;\n }\n .float-lg-end {\n float: right !important;\n }\n .float-lg-none {\n float: none !important;\n }\n .object-fit-lg-contain {\n -o-object-fit: contain !important;\n object-fit: contain !important;\n }\n .object-fit-lg-cover {\n -o-object-fit: cover !important;\n object-fit: cover !important;\n }\n .object-fit-lg-fill {\n -o-object-fit: fill !important;\n object-fit: fill !important;\n }\n .object-fit-lg-scale {\n -o-object-fit: scale-down !important;\n object-fit: scale-down !important;\n }\n .object-fit-lg-none {\n -o-object-fit: none !important;\n object-fit: none !important;\n }\n .d-lg-inline {\n display: inline !important;\n }\n .d-lg-inline-block {\n display: inline-block !important;\n }\n .d-lg-block {\n display: block !important;\n }\n .d-lg-grid {\n display: grid !important;\n }\n .d-lg-inline-grid {\n display: inline-grid !important;\n }\n .d-lg-table {\n display: table !important;\n }\n .d-lg-table-row {\n display: table-row !important;\n }\n .d-lg-table-cell {\n display: table-cell !important;\n }\n .d-lg-flex {\n display: flex !important;\n }\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n .d-lg-none {\n display: none !important;\n }\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n .flex-lg-row {\n flex-direction: row !important;\n }\n .flex-lg-column {\n flex-direction: column !important;\n }\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n .justify-content-lg-center {\n justify-content: center !important;\n }\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n .justify-content-lg-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n .align-items-lg-center {\n align-items: center !important;\n }\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n .align-content-lg-center {\n align-content: center !important;\n }\n .align-content-lg-between {\n align-content: space-between !important;\n }\n .align-content-lg-around {\n align-content: space-around !important;\n }\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n .align-self-lg-auto {\n align-self: auto !important;\n }\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n .align-self-lg-center {\n align-self: center !important;\n }\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n .order-lg-first {\n order: -1 !important;\n }\n .order-lg-0 {\n order: 0 !important;\n }\n .order-lg-1 {\n order: 1 !important;\n }\n .order-lg-2 {\n order: 2 !important;\n }\n .order-lg-3 {\n order: 3 !important;\n }\n .order-lg-4 {\n order: 4 !important;\n }\n .order-lg-5 {\n order: 5 !important;\n }\n .order-lg-last {\n order: 6 !important;\n }\n .m-lg-0 {\n margin: 0 !important;\n }\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n .m-lg-3 {\n margin: 1rem !important;\n }\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n .m-lg-5 {\n margin: 3rem !important;\n }\n .m-lg-auto {\n margin: auto !important;\n }\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n .mt-lg-auto {\n margin-top: auto !important;\n }\n .me-lg-0 {\n margin-right: 0 !important;\n }\n .me-lg-1 {\n margin-right: 0.25rem !important;\n }\n .me-lg-2 {\n margin-right: 0.5rem !important;\n }\n .me-lg-3 {\n margin-right: 1rem !important;\n }\n .me-lg-4 {\n margin-right: 1.5rem !important;\n }\n .me-lg-5 {\n margin-right: 3rem !important;\n }\n .me-lg-auto {\n margin-right: auto !important;\n }\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n .ms-lg-0 {\n margin-left: 0 !important;\n }\n .ms-lg-1 {\n margin-left: 0.25rem !important;\n }\n .ms-lg-2 {\n margin-left: 0.5rem !important;\n }\n .ms-lg-3 {\n margin-left: 1rem !important;\n }\n .ms-lg-4 {\n margin-left: 1.5rem !important;\n }\n .ms-lg-5 {\n margin-left: 3rem !important;\n }\n .ms-lg-auto {\n margin-left: auto !important;\n }\n .p-lg-0 {\n padding: 0 !important;\n }\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n .p-lg-3 {\n padding: 1rem !important;\n }\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n .p-lg-5 {\n padding: 3rem !important;\n }\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n .pe-lg-0 {\n padding-right: 0 !important;\n }\n .pe-lg-1 {\n padding-right: 0.25rem !important;\n }\n .pe-lg-2 {\n padding-right: 0.5rem !important;\n }\n .pe-lg-3 {\n padding-right: 1rem !important;\n }\n .pe-lg-4 {\n padding-right: 1.5rem !important;\n }\n .pe-lg-5 {\n padding-right: 3rem !important;\n }\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n .ps-lg-0 {\n padding-left: 0 !important;\n }\n .ps-lg-1 {\n padding-left: 0.25rem !important;\n }\n .ps-lg-2 {\n padding-left: 0.5rem !important;\n }\n .ps-lg-3 {\n padding-left: 1rem !important;\n }\n .ps-lg-4 {\n padding-left: 1.5rem !important;\n }\n .ps-lg-5 {\n padding-left: 3rem !important;\n }\n .gap-lg-0 {\n gap: 0 !important;\n }\n .gap-lg-1 {\n gap: 0.25rem !important;\n }\n .gap-lg-2 {\n gap: 0.5rem !important;\n }\n .gap-lg-3 {\n gap: 1rem !important;\n }\n .gap-lg-4 {\n gap: 1.5rem !important;\n }\n .gap-lg-5 {\n gap: 3rem !important;\n }\n .row-gap-lg-0 {\n row-gap: 0 !important;\n }\n .row-gap-lg-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-lg-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-lg-3 {\n row-gap: 1rem !important;\n }\n .row-gap-lg-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-lg-5 {\n row-gap: 3rem !important;\n }\n .column-gap-lg-0 {\n -moz-column-gap: 0 !important;\n column-gap: 0 !important;\n }\n .column-gap-lg-1 {\n -moz-column-gap: 0.25rem !important;\n column-gap: 0.25rem !important;\n }\n .column-gap-lg-2 {\n -moz-column-gap: 0.5rem !important;\n column-gap: 0.5rem !important;\n }\n .column-gap-lg-3 {\n -moz-column-gap: 1rem !important;\n column-gap: 1rem !important;\n }\n .column-gap-lg-4 {\n -moz-column-gap: 1.5rem !important;\n column-gap: 1.5rem !important;\n }\n .column-gap-lg-5 {\n -moz-column-gap: 3rem !important;\n column-gap: 3rem !important;\n }\n .text-lg-start {\n text-align: left !important;\n }\n .text-lg-end {\n text-align: right !important;\n }\n .text-lg-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1200px) {\n .float-xl-start {\n float: left !important;\n }\n .float-xl-end {\n float: right !important;\n }\n .float-xl-none {\n float: none !important;\n }\n .object-fit-xl-contain {\n -o-object-fit: contain !important;\n object-fit: contain !important;\n }\n .object-fit-xl-cover {\n -o-object-fit: cover !important;\n object-fit: cover !important;\n }\n .object-fit-xl-fill {\n -o-object-fit: fill !important;\n object-fit: fill !important;\n }\n .object-fit-xl-scale {\n -o-object-fit: scale-down !important;\n object-fit: scale-down !important;\n }\n .object-fit-xl-none {\n -o-object-fit: none !important;\n object-fit: none !important;\n }\n .d-xl-inline {\n display: inline !important;\n }\n .d-xl-inline-block {\n display: inline-block !important;\n }\n .d-xl-block {\n display: block !important;\n }\n .d-xl-grid {\n display: grid !important;\n }\n .d-xl-inline-grid {\n display: inline-grid !important;\n }\n .d-xl-table {\n display: table !important;\n }\n .d-xl-table-row {\n display: table-row !important;\n }\n .d-xl-table-cell {\n display: table-cell !important;\n }\n .d-xl-flex {\n display: flex !important;\n }\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n .d-xl-none {\n display: none !important;\n }\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xl-row {\n flex-direction: row !important;\n }\n .flex-xl-column {\n flex-direction: column !important;\n }\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xl-center {\n justify-content: center !important;\n }\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n .justify-content-xl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n .align-items-xl-center {\n align-items: center !important;\n }\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n .align-content-xl-center {\n align-content: center !important;\n }\n .align-content-xl-between {\n align-content: space-between !important;\n }\n .align-content-xl-around {\n align-content: space-around !important;\n }\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n .align-self-xl-auto {\n align-self: auto !important;\n }\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n .align-self-xl-center {\n align-self: center !important;\n }\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n .order-xl-first {\n order: -1 !important;\n }\n .order-xl-0 {\n order: 0 !important;\n }\n .order-xl-1 {\n order: 1 !important;\n }\n .order-xl-2 {\n order: 2 !important;\n }\n .order-xl-3 {\n order: 3 !important;\n }\n .order-xl-4 {\n order: 4 !important;\n }\n .order-xl-5 {\n order: 5 !important;\n }\n .order-xl-last {\n order: 6 !important;\n }\n .m-xl-0 {\n margin: 0 !important;\n }\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n .m-xl-3 {\n margin: 1rem !important;\n }\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n .m-xl-5 {\n margin: 3rem !important;\n }\n .m-xl-auto {\n margin: auto !important;\n }\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n .mt-xl-auto {\n margin-top: auto !important;\n }\n .me-xl-0 {\n margin-right: 0 !important;\n }\n .me-xl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xl-3 {\n margin-right: 1rem !important;\n }\n .me-xl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xl-5 {\n margin-right: 3rem !important;\n }\n .me-xl-auto {\n margin-right: auto !important;\n }\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n .ms-xl-0 {\n margin-left: 0 !important;\n }\n .ms-xl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xl-3 {\n margin-left: 1rem !important;\n }\n .ms-xl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xl-5 {\n margin-left: 3rem !important;\n }\n .ms-xl-auto {\n margin-left: auto !important;\n }\n .p-xl-0 {\n padding: 0 !important;\n }\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n .p-xl-3 {\n padding: 1rem !important;\n }\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n .p-xl-5 {\n padding: 3rem !important;\n }\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n .pe-xl-0 {\n padding-right: 0 !important;\n }\n .pe-xl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xl-3 {\n padding-right: 1rem !important;\n }\n .pe-xl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xl-5 {\n padding-right: 3rem !important;\n }\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xl-0 {\n padding-left: 0 !important;\n }\n .ps-xl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xl-3 {\n padding-left: 1rem !important;\n }\n .ps-xl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xl-5 {\n padding-left: 3rem !important;\n }\n .gap-xl-0 {\n gap: 0 !important;\n }\n .gap-xl-1 {\n gap: 0.25rem !important;\n }\n .gap-xl-2 {\n gap: 0.5rem !important;\n }\n .gap-xl-3 {\n gap: 1rem !important;\n }\n .gap-xl-4 {\n gap: 1.5rem !important;\n }\n .gap-xl-5 {\n gap: 3rem !important;\n }\n .row-gap-xl-0 {\n row-gap: 0 !important;\n }\n .row-gap-xl-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-xl-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-xl-3 {\n row-gap: 1rem !important;\n }\n .row-gap-xl-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-xl-5 {\n row-gap: 3rem !important;\n }\n .column-gap-xl-0 {\n -moz-column-gap: 0 !important;\n column-gap: 0 !important;\n }\n .column-gap-xl-1 {\n -moz-column-gap: 0.25rem !important;\n column-gap: 0.25rem !important;\n }\n .column-gap-xl-2 {\n -moz-column-gap: 0.5rem !important;\n column-gap: 0.5rem !important;\n }\n .column-gap-xl-3 {\n -moz-column-gap: 1rem !important;\n column-gap: 1rem !important;\n }\n .column-gap-xl-4 {\n -moz-column-gap: 1.5rem !important;\n column-gap: 1.5rem !important;\n }\n .column-gap-xl-5 {\n -moz-column-gap: 3rem !important;\n column-gap: 3rem !important;\n }\n .text-xl-start {\n text-align: left !important;\n }\n .text-xl-end {\n text-align: right !important;\n }\n .text-xl-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1400px) {\n .float-xxl-start {\n float: left !important;\n }\n .float-xxl-end {\n float: right !important;\n }\n .float-xxl-none {\n float: none !important;\n }\n .object-fit-xxl-contain {\n -o-object-fit: contain !important;\n object-fit: contain !important;\n }\n .object-fit-xxl-cover {\n -o-object-fit: cover !important;\n object-fit: cover !important;\n }\n .object-fit-xxl-fill {\n -o-object-fit: fill !important;\n object-fit: fill !important;\n }\n .object-fit-xxl-scale {\n -o-object-fit: scale-down !important;\n object-fit: scale-down !important;\n }\n .object-fit-xxl-none {\n -o-object-fit: none !important;\n object-fit: none !important;\n }\n .d-xxl-inline {\n display: inline !important;\n }\n .d-xxl-inline-block {\n display: inline-block !important;\n }\n .d-xxl-block {\n display: block !important;\n }\n .d-xxl-grid {\n display: grid !important;\n }\n .d-xxl-inline-grid {\n display: inline-grid !important;\n }\n .d-xxl-table {\n display: table !important;\n }\n .d-xxl-table-row {\n display: table-row !important;\n }\n .d-xxl-table-cell {\n display: table-cell !important;\n }\n .d-xxl-flex {\n display: flex !important;\n }\n .d-xxl-inline-flex {\n display: inline-flex !important;\n }\n .d-xxl-none {\n display: none !important;\n }\n .flex-xxl-fill {\n flex: 1 1 auto !important;\n }\n .flex-xxl-row {\n flex-direction: row !important;\n }\n .flex-xxl-column {\n flex-direction: column !important;\n }\n .flex-xxl-row-reverse {\n flex-direction: row-reverse !important;\n }\n .flex-xxl-column-reverse {\n flex-direction: column-reverse !important;\n }\n .flex-xxl-grow-0 {\n flex-grow: 0 !important;\n }\n .flex-xxl-grow-1 {\n flex-grow: 1 !important;\n }\n .flex-xxl-shrink-0 {\n flex-shrink: 0 !important;\n }\n .flex-xxl-shrink-1 {\n flex-shrink: 1 !important;\n }\n .flex-xxl-wrap {\n flex-wrap: wrap !important;\n }\n .flex-xxl-nowrap {\n flex-wrap: nowrap !important;\n }\n .flex-xxl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n .justify-content-xxl-start {\n justify-content: flex-start !important;\n }\n .justify-content-xxl-end {\n justify-content: flex-end !important;\n }\n .justify-content-xxl-center {\n justify-content: center !important;\n }\n .justify-content-xxl-between {\n justify-content: space-between !important;\n }\n .justify-content-xxl-around {\n justify-content: space-around !important;\n }\n .justify-content-xxl-evenly {\n justify-content: space-evenly !important;\n }\n .align-items-xxl-start {\n align-items: flex-start !important;\n }\n .align-items-xxl-end {\n align-items: flex-end !important;\n }\n .align-items-xxl-center {\n align-items: center !important;\n }\n .align-items-xxl-baseline {\n align-items: baseline !important;\n }\n .align-items-xxl-stretch {\n align-items: stretch !important;\n }\n .align-content-xxl-start {\n align-content: flex-start !important;\n }\n .align-content-xxl-end {\n align-content: flex-end !important;\n }\n .align-content-xxl-center {\n align-content: center !important;\n }\n .align-content-xxl-between {\n align-content: space-between !important;\n }\n .align-content-xxl-around {\n align-content: space-around !important;\n }\n .align-content-xxl-stretch {\n align-content: stretch !important;\n }\n .align-self-xxl-auto {\n align-self: auto !important;\n }\n .align-self-xxl-start {\n align-self: flex-start !important;\n }\n .align-self-xxl-end {\n align-self: flex-end !important;\n }\n .align-self-xxl-center {\n align-self: center !important;\n }\n .align-self-xxl-baseline {\n align-self: baseline !important;\n }\n .align-self-xxl-stretch {\n align-self: stretch !important;\n }\n .order-xxl-first {\n order: -1 !important;\n }\n .order-xxl-0 {\n order: 0 !important;\n }\n .order-xxl-1 {\n order: 1 !important;\n }\n .order-xxl-2 {\n order: 2 !important;\n }\n .order-xxl-3 {\n order: 3 !important;\n }\n .order-xxl-4 {\n order: 4 !important;\n }\n .order-xxl-5 {\n order: 5 !important;\n }\n .order-xxl-last {\n order: 6 !important;\n }\n .m-xxl-0 {\n margin: 0 !important;\n }\n .m-xxl-1 {\n margin: 0.25rem !important;\n }\n .m-xxl-2 {\n margin: 0.5rem !important;\n }\n .m-xxl-3 {\n margin: 1rem !important;\n }\n .m-xxl-4 {\n margin: 1.5rem !important;\n }\n .m-xxl-5 {\n margin: 3rem !important;\n }\n .m-xxl-auto {\n margin: auto !important;\n }\n .mx-xxl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n .mx-xxl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n .mx-xxl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n .mx-xxl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n .mx-xxl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n .mx-xxl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n .mx-xxl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n .my-xxl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n .my-xxl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n .my-xxl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n .my-xxl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n .my-xxl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n .my-xxl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n .my-xxl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n .mt-xxl-0 {\n margin-top: 0 !important;\n }\n .mt-xxl-1 {\n margin-top: 0.25rem !important;\n }\n .mt-xxl-2 {\n margin-top: 0.5rem !important;\n }\n .mt-xxl-3 {\n margin-top: 1rem !important;\n }\n .mt-xxl-4 {\n margin-top: 1.5rem !important;\n }\n .mt-xxl-5 {\n margin-top: 3rem !important;\n }\n .mt-xxl-auto {\n margin-top: auto !important;\n }\n .me-xxl-0 {\n margin-right: 0 !important;\n }\n .me-xxl-1 {\n margin-right: 0.25rem !important;\n }\n .me-xxl-2 {\n margin-right: 0.5rem !important;\n }\n .me-xxl-3 {\n margin-right: 1rem !important;\n }\n .me-xxl-4 {\n margin-right: 1.5rem !important;\n }\n .me-xxl-5 {\n margin-right: 3rem !important;\n }\n .me-xxl-auto {\n margin-right: auto !important;\n }\n .mb-xxl-0 {\n margin-bottom: 0 !important;\n }\n .mb-xxl-1 {\n margin-bottom: 0.25rem !important;\n }\n .mb-xxl-2 {\n margin-bottom: 0.5rem !important;\n }\n .mb-xxl-3 {\n margin-bottom: 1rem !important;\n }\n .mb-xxl-4 {\n margin-bottom: 1.5rem !important;\n }\n .mb-xxl-5 {\n margin-bottom: 3rem !important;\n }\n .mb-xxl-auto {\n margin-bottom: auto !important;\n }\n .ms-xxl-0 {\n margin-left: 0 !important;\n }\n .ms-xxl-1 {\n margin-left: 0.25rem !important;\n }\n .ms-xxl-2 {\n margin-left: 0.5rem !important;\n }\n .ms-xxl-3 {\n margin-left: 1rem !important;\n }\n .ms-xxl-4 {\n margin-left: 1.5rem !important;\n }\n .ms-xxl-5 {\n margin-left: 3rem !important;\n }\n .ms-xxl-auto {\n margin-left: auto !important;\n }\n .p-xxl-0 {\n padding: 0 !important;\n }\n .p-xxl-1 {\n padding: 0.25rem !important;\n }\n .p-xxl-2 {\n padding: 0.5rem !important;\n }\n .p-xxl-3 {\n padding: 1rem !important;\n }\n .p-xxl-4 {\n padding: 1.5rem !important;\n }\n .p-xxl-5 {\n padding: 3rem !important;\n }\n .px-xxl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n .px-xxl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n .px-xxl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n .px-xxl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n .px-xxl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n .px-xxl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n .py-xxl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n .py-xxl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n .py-xxl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n .py-xxl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n .py-xxl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n .py-xxl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n .pt-xxl-0 {\n padding-top: 0 !important;\n }\n .pt-xxl-1 {\n padding-top: 0.25rem !important;\n }\n .pt-xxl-2 {\n padding-top: 0.5rem !important;\n }\n .pt-xxl-3 {\n padding-top: 1rem !important;\n }\n .pt-xxl-4 {\n padding-top: 1.5rem !important;\n }\n .pt-xxl-5 {\n padding-top: 3rem !important;\n }\n .pe-xxl-0 {\n padding-right: 0 !important;\n }\n .pe-xxl-1 {\n padding-right: 0.25rem !important;\n }\n .pe-xxl-2 {\n padding-right: 0.5rem !important;\n }\n .pe-xxl-3 {\n padding-right: 1rem !important;\n }\n .pe-xxl-4 {\n padding-right: 1.5rem !important;\n }\n .pe-xxl-5 {\n padding-right: 3rem !important;\n }\n .pb-xxl-0 {\n padding-bottom: 0 !important;\n }\n .pb-xxl-1 {\n padding-bottom: 0.25rem !important;\n }\n .pb-xxl-2 {\n padding-bottom: 0.5rem !important;\n }\n .pb-xxl-3 {\n padding-bottom: 1rem !important;\n }\n .pb-xxl-4 {\n padding-bottom: 1.5rem !important;\n }\n .pb-xxl-5 {\n padding-bottom: 3rem !important;\n }\n .ps-xxl-0 {\n padding-left: 0 !important;\n }\n .ps-xxl-1 {\n padding-left: 0.25rem !important;\n }\n .ps-xxl-2 {\n padding-left: 0.5rem !important;\n }\n .ps-xxl-3 {\n padding-left: 1rem !important;\n }\n .ps-xxl-4 {\n padding-left: 1.5rem !important;\n }\n .ps-xxl-5 {\n padding-left: 3rem !important;\n }\n .gap-xxl-0 {\n gap: 0 !important;\n }\n .gap-xxl-1 {\n gap: 0.25rem !important;\n }\n .gap-xxl-2 {\n gap: 0.5rem !important;\n }\n .gap-xxl-3 {\n gap: 1rem !important;\n }\n .gap-xxl-4 {\n gap: 1.5rem !important;\n }\n .gap-xxl-5 {\n gap: 3rem !important;\n }\n .row-gap-xxl-0 {\n row-gap: 0 !important;\n }\n .row-gap-xxl-1 {\n row-gap: 0.25rem !important;\n }\n .row-gap-xxl-2 {\n row-gap: 0.5rem !important;\n }\n .row-gap-xxl-3 {\n row-gap: 1rem !important;\n }\n .row-gap-xxl-4 {\n row-gap: 1.5rem !important;\n }\n .row-gap-xxl-5 {\n row-gap: 3rem !important;\n }\n .column-gap-xxl-0 {\n -moz-column-gap: 0 !important;\n column-gap: 0 !important;\n }\n .column-gap-xxl-1 {\n -moz-column-gap: 0.25rem !important;\n column-gap: 0.25rem !important;\n }\n .column-gap-xxl-2 {\n -moz-column-gap: 0.5rem !important;\n column-gap: 0.5rem !important;\n }\n .column-gap-xxl-3 {\n -moz-column-gap: 1rem !important;\n column-gap: 1rem !important;\n }\n .column-gap-xxl-4 {\n -moz-column-gap: 1.5rem !important;\n column-gap: 1.5rem !important;\n }\n .column-gap-xxl-5 {\n -moz-column-gap: 3rem !important;\n column-gap: 3rem !important;\n }\n .text-xxl-start {\n text-align: left !important;\n }\n .text-xxl-end {\n text-align: right !important;\n }\n .text-xxl-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1200px) {\n .fs-1 {\n font-size: 2.5rem !important;\n }\n .fs-2 {\n font-size: 2rem !important;\n }\n .fs-3 {\n font-size: 1.75rem !important;\n }\n .fs-4 {\n font-size: 1.5rem !important;\n }\n}\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n .d-print-inline-block {\n display: inline-block !important;\n }\n .d-print-block {\n display: block !important;\n }\n .d-print-grid {\n display: grid !important;\n }\n .d-print-inline-grid {\n display: inline-grid !important;\n }\n .d-print-table {\n display: table !important;\n }\n .d-print-table-row {\n display: table-row !important;\n }\n .d-print-table-cell {\n display: table-cell !important;\n }\n .d-print-flex {\n display: flex !important;\n }\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n .d-print-none {\n display: none !important;\n }\n}\n\n/*# sourceMappingURL=bootstrap.css.map */", - "// stylelint-disable scss/dimension-no-non-numeric-values\n\n// SCSS RFS mixin\n//\n// Automated responsive values for font sizes, paddings, margins and much more\n//\n// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE)\n\n// Configuration\n\n// Base value\n$rfs-base-value: 1.25rem !default;\n$rfs-unit: rem !default;\n\n@if $rfs-unit != rem and $rfs-unit != px {\n @error \"`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`.\";\n}\n\n// Breakpoint at where values start decreasing if screen width is smaller\n$rfs-breakpoint: 1200px !default;\n$rfs-breakpoint-unit: px !default;\n\n@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {\n @error \"`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.\";\n}\n\n// Resize values based on screen height and width\n$rfs-two-dimensional: false !default;\n\n// Factor of decrease\n$rfs-factor: 10 !default;\n\n@if type-of($rfs-factor) != number or $rfs-factor <= 1 {\n @error \"`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1.\";\n}\n\n// Mode. Possibilities: \"min-media-query\", \"max-media-query\"\n$rfs-mode: min-media-query !default;\n\n// Generate enable or disable classes. Possibilities: false, \"enable\" or \"disable\"\n$rfs-class: false !default;\n\n// 1 rem = $rfs-rem-value px\n$rfs-rem-value: 16 !default;\n\n// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14\n$rfs-safari-iframe-resize-bug-fix: false !default;\n\n// Disable RFS by setting $enable-rfs to false\n$enable-rfs: true !default;\n\n// Cache $rfs-base-value unit\n$rfs-base-value-unit: unit($rfs-base-value);\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n\n// Remove px-unit from $rfs-base-value for calculations\n@if $rfs-base-value-unit == px {\n $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);\n}\n@else if $rfs-base-value-unit == rem {\n $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));\n}\n\n// Cache $rfs-breakpoint unit to prevent multiple calls\n$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);\n\n// Remove unit from $rfs-breakpoint for calculations\n@if $rfs-breakpoint-unit-cache == px {\n $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);\n}\n@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == \"em\" {\n $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));\n}\n\n// Calculate the media query value\n$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});\n$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width);\n$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height);\n\n// Internal mixin used to determine which media query needs to be used\n@mixin _rfs-media-query {\n @if $rfs-two-dimensional {\n @if $rfs-mode == max-media-query {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {\n @content;\n }\n }\n}\n\n// Internal mixin that adds disable classes to the selector if needed.\n@mixin _rfs-rule {\n @if $rfs-class == disable and $rfs-mode == max-media-query {\n // Adding an extra class increases specificity, which prevents the media query to override the property\n &,\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @else if $rfs-class == enable and $rfs-mode == min-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Internal mixin that adds enable classes to the selector if needed.\n@mixin _rfs-media-query-rule {\n\n @if $rfs-class == enable {\n @if $rfs-mode == min-media-query {\n @content;\n }\n\n @include _rfs-media-query () {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n }\n @else {\n @if $rfs-class == disable and $rfs-mode == min-media-query {\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @include _rfs-media-query () {\n @content;\n }\n }\n}\n\n// Helper function to get the formatted non-responsive value\n@function rfs-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: \"\";\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + \" 0\";\n }\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n @if $unit == px {\n // Convert to rem if needed\n $val: $val + \" \" + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);\n }\n @else if $unit == rem {\n // Convert to px if needed\n $val: $val + \" \" + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);\n } @else {\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n $val: $val + \" \" + $value;\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// Helper function to get the responsive value calculated by RFS\n@function rfs-fluid-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: \"\";\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + \" 0\";\n } @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n @if not $unit or $unit != px and $unit != rem {\n $val: $val + \" \" + $value;\n } @else {\n // Remove unit from $value for calculations\n $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));\n\n // Only add the media query if the value is greater than the minimum value\n @if abs($value) <= $rfs-base-value or not $enable-rfs {\n $val: $val + \" \" + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);\n }\n @else {\n // Calculate the minimum value\n $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor);\n\n // Calculate difference between $value and the minimum value\n $value-diff: abs($value) - $value-min;\n\n // Base value formatting\n $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px);\n\n // Use negative value if needed\n $min-width: if($value < 0, -$min-width, $min-width);\n\n // Use `vmin` if two-dimensional is enabled\n $variable-unit: if($rfs-two-dimensional, vmin, vw);\n\n // Calculate the variable width between 0 and $rfs-breakpoint\n $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};\n\n // Return the calculated value\n $val: $val + \" calc(\" + $min-width + if($value < 0, \" - \", \" + \") + $variable-width + \")\";\n }\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// RFS mixin\n@mixin rfs($values, $property: font-size) {\n @if $values != null {\n $val: rfs-value($values);\n $fluid-val: rfs-fluid-value($values);\n\n // Do not print the media query if responsive & non-responsive values are the same\n @if $val == $fluid-val {\n #{$property}: $val;\n }\n @else {\n @include _rfs-rule () {\n #{$property}: if($rfs-mode == max-media-query, $val, $fluid-val);\n\n // Include safari iframe resize fix if needed\n min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);\n }\n\n @include _rfs-media-query-rule () {\n #{$property}: if($rfs-mode == max-media-query, $fluid-val, $val);\n }\n }\n }\n}\n\n// Shorthand helper mixins\n@mixin font-size($value) {\n @include rfs($value);\n}\n\n@mixin padding($value) {\n @include rfs($value, padding);\n}\n\n@mixin padding-top($value) {\n @include rfs($value, padding-top);\n}\n\n@mixin padding-right($value) {\n @include rfs($value, padding-right);\n}\n\n@mixin padding-bottom($value) {\n @include rfs($value, padding-bottom);\n}\n\n@mixin padding-left($value) {\n @include rfs($value, padding-left);\n}\n\n@mixin margin($value) {\n @include rfs($value, margin);\n}\n\n@mixin margin-top($value) {\n @include rfs($value, margin-top);\n}\n\n@mixin margin-right($value) {\n @include rfs($value, margin-right);\n}\n\n@mixin margin-bottom($value) {\n @include rfs($value, margin-bottom);\n}\n\n@mixin margin-left($value) {\n @include rfs($value, margin-left);\n}\n", - "// scss-docs-start color-mode-mixin\n@mixin color-mode($mode: light, $root: false) {\n @if $color-mode-type == \"media-query\" {\n @if $root == true {\n @media (prefers-color-scheme: $mode) {\n :root {\n @content;\n }\n }\n } @else {\n @media (prefers-color-scheme: $mode) {\n @content;\n }\n }\n } @else {\n [data-bs-theme=\"#{$mode}\"] {\n @content;\n }\n }\n}\n// scss-docs-end color-mode-mixin\n", - "// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n\n// Root\n//\n// Ability to the value of the root font sizes, affecting the value of `rem`.\n// null by default, thus nothing is generated.\n\n:root {\n @if $font-size-root != null {\n @include font-size(var(--#{$prefix}root-font-size));\n }\n\n @if $enable-smooth-scroll {\n @media (prefers-reduced-motion: no-preference) {\n scroll-behavior: smooth;\n }\n }\n}\n\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Prevent adjustments of font size after orientation changes in iOS.\n// 4. Change the default tap highlight to be completely transparent in iOS.\n\n// scss-docs-start reboot-body-rules\nbody {\n margin: 0; // 1\n font-family: var(--#{$prefix}body-font-family);\n @include font-size(var(--#{$prefix}body-font-size));\n font-weight: var(--#{$prefix}body-font-weight);\n line-height: var(--#{$prefix}body-line-height);\n color: var(--#{$prefix}body-color);\n text-align: var(--#{$prefix}body-text-align);\n background-color: var(--#{$prefix}body-bg); // 2\n -webkit-text-size-adjust: 100%; // 3\n -webkit-tap-highlight-color: rgba($black, 0); // 4\n}\n// scss-docs-end reboot-body-rules\n\n\n// Content grouping\n//\n// 1. Reset Firefox's gray color\n\nhr {\n margin: $hr-margin-y 0;\n color: $hr-color; // 1\n border: 0;\n border-top: $hr-border-width solid $hr-border-color;\n opacity: $hr-opacity;\n}\n\n\n// Typography\n//\n// 1. Remove top margins from headings\n// By default, `

    `-`

    ` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: var(--#{$prefix}heading-color);\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

    `s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 2. Add explicit cursor to indicate changed behavior.\n// 3. Prevent the text-decoration to be skipped.\n\nabbr[title] {\n text-decoration: underline dotted; // 1\n cursor: help; // 2\n text-decoration-skip-ink: none; // 3\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n color: var(--#{$prefix}highlight-color);\n background-color: var(--#{$prefix}highlight-bg);\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1));\n text-decoration: $link-decoration;\n\n &:hover {\n --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb);\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: var(--#{$prefix}code-color);\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `

    ').appendTo($this); + } + oSettings.nTHead = thead[0]; + $('tr', thead).addClass(oClasses.thead.row); + + var tbody = $this.children('tbody'); + if ( tbody.length === 0 ) { + tbody = $('').insertAfter(thead); + } + oSettings.nTBody = tbody[0]; + + var tfoot = $this.children('tfoot'); + if ( tfoot.length === 0 ) { + // If we are a scrolling table, and no footer has been given, then we need to create + // a tfoot element for the caption element to be appended to + tfoot = $('').appendTo($this); + } + oSettings.nTFoot = tfoot[0]; + $('tr', tfoot).addClass(oClasses.tfoot.row); + + // Copy the data index array + oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); + + // Initialisation complete - table can be drawn + oSettings.bInitialised = true; + + // Language definitions + var oLanguage = oSettings.oLanguage; + $.extend( true, oLanguage, oInit.oLanguage ); + + if ( oLanguage.sUrl ) { + // Get the language definitions from a file + $.ajax( { + dataType: 'json', + url: oLanguage.sUrl, + success: function ( json ) { + _fnCamelToHungarian( defaults.oLanguage, json ); + $.extend( true, oLanguage, json, oSettings.oInit.oLanguage ); + + _fnCallbackFire( oSettings, null, 'i18n', [oSettings], true); + _fnInitialise( oSettings ); + }, + error: function () { + // Error occurred loading language file + _fnLog( oSettings, 0, 'i18n file loading error', 21 ); + + // Continue on as best we can + _fnInitialise( oSettings ); + } + } ); + } + else { + _fnCallbackFire( oSettings, null, 'i18n', [oSettings]); + _fnInitialise( oSettings ); + } + } ); + _that = null; + return this; + }; + + + + /** + * DataTables extensions + * + * This namespace acts as a collection area for plug-ins that can be used to + * extend DataTables capabilities. Indeed many of the build in methods + * use this method to provide their own capabilities (sorting methods for + * example). + * + * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy + * reasons + * + * @namespace + */ + DataTable.ext = _ext = { + /** + * Buttons. For use with the Buttons extension for DataTables. This is + * defined here so other extensions can define buttons regardless of load + * order. It is _not_ used by DataTables core. + * + * @type object + * @default {} + */ + buttons: {}, + + + /** + * Element class names + * + * @type object + * @default {} + */ + classes: {}, + + + /** + * DataTables build type (expanded by the download builder) + * + * @type string + */ + builder: "-source-", + + + /** + * Error reporting. + * + * How should DataTables report an error. Can take the value 'alert', + * 'throw', 'none' or a function. + * + * @type string|function + * @default alert + */ + errMode: "alert", + + + /** + * Legacy so v1 plug-ins don't throw js errors on load + */ + feature: [], + + /** + * Feature plug-ins. + * + * This is an object of callbacks which provide the features for DataTables + * to be initialised via the `layout` option. + */ + features: {}, + + + /** + * Row searching. + * + * This method of searching is complimentary to the default type based + * searching, and a lot more comprehensive as it allows you complete control + * over the searching logic. Each element in this array is a function + * (parameters described below) that is called for every row in the table, + * and your logic decides if it should be included in the searching data set + * or not. + * + * Searching functions have the following input parameters: + * + * 1. `{object}` DataTables settings object: see + * {@link DataTable.models.oSettings} + * 2. `{array|object}` Data for the row to be processed (same as the + * original format that was passed in as the data source, or an array + * from a DOM data source + * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which + * can be useful to retrieve the `TR` element if you need DOM interaction. + * + * And the following return is expected: + * + * * {boolean} Include the row in the searched result set (true) or not + * (false) + * + * Note that as with the main search ability in DataTables, technically this + * is "filtering", since it is subtractive. However, for consistency in + * naming we call it searching here. + * + * @type array + * @default [] + * + * @example + * // The following example shows custom search being applied to the + * // fourth column (i.e. the data[3] index) based on two input values + * // from the end-user, matching the data in a certain range. + * $.fn.dataTable.ext.search.push( + * function( settings, data, dataIndex ) { + * var min = document.getElementById('min').value * 1; + * var max = document.getElementById('max').value * 1; + * var version = data[3] == "-" ? 0 : data[3]*1; + * + * if ( min == "" && max == "" ) { + * return true; + * } + * else if ( min == "" && version < max ) { + * return true; + * } + * else if ( min < version && "" == max ) { + * return true; + * } + * else if ( min < version && version < max ) { + * return true; + * } + * return false; + * } + * ); + */ + search: [], + + + /** + * Selector extensions + * + * The `selector` option can be used to extend the options available for the + * selector modifier options (`selector-modifier` object data type) that + * each of the three built in selector types offer (row, column and cell + + * their plural counterparts). For example the Select extension uses this + * mechanism to provide an option to select only rows, columns and cells + * that have been marked as selected by the end user (`{selected: true}`), + * which can be used in conjunction with the existing built in selector + * options. + * + * Each property is an array to which functions can be pushed. The functions + * take three attributes: + * + * * Settings object for the host table + * * Options object (`selector-modifier` object type) + * * Array of selected item indexes + * + * The return is an array of the resulting item indexes after the custom + * selector has been applied. + * + * @type object + */ + selector: { + cell: [], + column: [], + row: [] + }, + + + /** + * Legacy configuration options. Enable and disable legacy options that + * are available in DataTables. + * + * @type object + */ + legacy: { + /** + * Enable / disable DataTables 1.9 compatible server-side processing + * requests + * + * @type boolean + * @default null + */ + ajax: null + }, + + + /** + * Pagination plug-in methods. + * + * Each entry in this object is a function and defines which buttons should + * be shown by the pagination rendering method that is used for the table: + * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the + * buttons are displayed in the document, while the functions here tell it + * what buttons to display. This is done by returning an array of button + * descriptions (what each button will do). + * + * Pagination types (the four built in options and any additional plug-in + * options defined here) can be used through the `paginationType` + * initialisation parameter. + * + * The functions defined take two parameters: + * + * 1. `{int} page` The current page index + * 2. `{int} pages` The number of pages in the table + * + * Each function is expected to return an array where each element of the + * array can be one of: + * + * * `first` - Jump to first page when activated + * * `last` - Jump to last page when activated + * * `previous` - Show previous page when activated + * * `next` - Show next page when activated + * * `{int}` - Show page of the index given + * * `{array}` - A nested array containing the above elements to add a + * containing 'DIV' element (might be useful for styling). + * + * Note that DataTables v1.9- used this object slightly differently whereby + * an object with two functions would be defined for each plug-in. That + * ability is still supported by DataTables 1.10+ to provide backwards + * compatibility, but this option of use is now decremented and no longer + * documented in DataTables 1.10+. + * + * @type object + * @default {} + * + * @example + * // Show previous, next and current page buttons only + * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { + * return [ 'previous', page, 'next' ]; + * }; + */ + pager: {}, + + + renderer: { + pageButton: {}, + header: {} + }, + + + /** + * Ordering plug-ins - custom data source + * + * The extension options for ordering of data available here is complimentary + * to the default type based ordering that DataTables typically uses. It + * allows much greater control over the the data that is being used to + * order a column, but is necessarily therefore more complex. + * + * This type of ordering is useful if you want to do ordering based on data + * live from the DOM (for example the contents of an 'input' element) rather + * than just the static string that DataTables knows of. + * + * The way these plug-ins work is that you create an array of the values you + * wish to be ordering for the column in question and then return that + * array. The data in the array much be in the index order of the rows in + * the table (not the currently ordering order!). Which order data gathering + * function is run here depends on the `dt-init columns.orderDataType` + * parameter that is used for the column (if any). + * + * The functions defined take two parameters: + * + * 1. `{object}` DataTables settings object: see + * {@link DataTable.models.oSettings} + * 2. `{int}` Target column index + * + * Each function is expected to return an array: + * + * * `{array}` Data for the column to be ordering upon + * + * @type array + * + * @example + * // Ordering using `input` node values + * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) + * { + * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { + * return $('input', td).val(); + * } ); + * } + */ + order: {}, + + + /** + * Type based plug-ins. + * + * Each column in DataTables has a type assigned to it, either by automatic + * detection or by direct assignment using the `type` option for the column. + * The type of a column will effect how it is ordering and search (plug-ins + * can also make use of the column type if required). + * + * @namespace + */ + type: { + /** + * Automatic column class assignment + */ + className: {}, + + /** + * Type detection functions. + * + * The functions defined in this object are used to automatically detect + * a column's type, making initialisation of DataTables super easy, even + * when complex data is in the table. + * + * The functions defined take two parameters: + * + * 1. `{*}` Data from the column cell to be analysed + * 2. `{settings}` DataTables settings object. This can be used to + * perform context specific type detection - for example detection + * based on language settings such as using a comma for a decimal + * place. Generally speaking the options from the settings will not + * be required + * + * Each function is expected to return: + * + * * `{string|null}` Data type detected, or null if unknown (and thus + * pass it on to the other type detection functions. + * + * @type array + * + * @example + * // Currency type detection plug-in: + * $.fn.dataTable.ext.type.detect.push( + * function ( data, settings ) { + * // Check the numeric part + * if ( ! data.substring(1).match(/[0-9]/) ) { + * return null; + * } + * + * // Check prefixed by currency + * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { + * return 'currency'; + * } + * return null; + * } + * ); + */ + detect: [], + + /** + * Automatic renderer assignment + */ + render: {}, + + + /** + * Type based search formatting. + * + * The type based searching functions can be used to pre-format the + * data to be search on. For example, it can be used to strip HTML + * tags or to de-format telephone numbers for numeric only searching. + * + * Note that is a search is not defined for a column of a given type, + * no search formatting will be performed. + * + * Pre-processing of searching data plug-ins - When you assign the sType + * for a column (or have it automatically detected for you by DataTables + * or a type detection plug-in), you will typically be using this for + * custom sorting, but it can also be used to provide custom searching + * by allowing you to pre-processing the data and returning the data in + * the format that should be searched upon. This is done by adding + * functions this object with a parameter name which matches the sType + * for that target column. This is the corollary of afnSortData + * for searching data. + * + * The functions defined take a single parameter: + * + * 1. `{*}` Data from the column cell to be prepared for searching + * + * Each function is expected to return: + * + * * `{string|null}` Formatted string that will be used for the searching. + * + * @type object + * @default {} + * + * @example + * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { + * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); + * } + */ + search: {}, + + + /** + * Type based ordering. + * + * The column type tells DataTables what ordering to apply to the table + * when a column is sorted upon. The order for each type that is defined, + * is defined by the functions available in this object. + * + * Each ordering option can be described by three properties added to + * this object: + * + * * `{type}-pre` - Pre-formatting function + * * `{type}-asc` - Ascending order function + * * `{type}-desc` - Descending order function + * + * All three can be used together, only `{type}-pre` or only + * `{type}-asc` and `{type}-desc` together. It is generally recommended + * that only `{type}-pre` is used, as this provides the optimal + * implementation in terms of speed, although the others are provided + * for compatibility with existing Javascript sort functions. + * + * `{type}-pre`: Functions defined take a single parameter: + * + * 1. `{*}` Data from the column cell to be prepared for ordering + * + * And return: + * + * * `{*}` Data to be sorted upon + * + * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort + * functions, taking two parameters: + * + * 1. `{*}` Data to compare to the second parameter + * 2. `{*}` Data to compare to the first parameter + * + * And returning: + * + * * `{*}` Ordering match: <0 if first parameter should be sorted lower + * than the second parameter, ===0 if the two parameters are equal and + * >0 if the first parameter should be sorted height than the second + * parameter. + * + * @type object + * @default {} + * + * @example + * // Numeric ordering of formatted numbers with a pre-formatter + * $.extend( $.fn.dataTable.ext.type.order, { + * "string-pre": function(x) { + * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); + * return parseFloat( a ); + * } + * } ); + * + * @example + * // Case-sensitive string ordering, with no pre-formatting method + * $.extend( $.fn.dataTable.ext.order, { + * "string-case-asc": function(x,y) { + * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + * }, + * "string-case-desc": function(x,y) { + * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + * } + * } ); + */ + order: {} + }, + + /** + * Unique DataTables instance counter + * + * @type int + * @private + */ + _unique: 0, + + + // + // Depreciated + // The following properties are retained for backwards compatibility only. + // The should not be used in new projects and will be removed in a future + // version + // + + /** + * Version check function. + * @type function + * @depreciated Since 1.10 + */ + fnVersionCheck: DataTable.fnVersionCheck, + + + /** + * Index for what 'this' index API functions should use + * @type int + * @deprecated Since v1.10 + */ + iApiIndex: 0, + + + /** + * Software version + * @type string + * @deprecated Since v1.10 + */ + sVersion: DataTable.version + }; + + + // + // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts + // + $.extend( _ext, { + afnFiltering: _ext.search, + aTypes: _ext.type.detect, + ofnSearch: _ext.type.search, + oSort: _ext.type.order, + afnSortData: _ext.order, + aoFeatures: _ext.feature, + oStdClasses: _ext.classes, + oPagination: _ext.pager + } ); + + + $.extend( DataTable.ext.classes, { + container: 'dt-container', + empty: { + row: 'dt-empty' + }, + info: { + container: 'dt-info' + }, + layout: { + row: 'dt-layout-row', + cell: 'dt-layout-cell', + tableRow: 'dt-layout-table', + tableCell: '', + start: 'dt-layout-start', + end: 'dt-layout-end', + full: 'dt-layout-full' + }, + length: { + container: 'dt-length', + select: 'dt-input' + }, + order: { + canAsc: 'dt-orderable-asc', + canDesc: 'dt-orderable-desc', + isAsc: 'dt-ordering-asc', + isDesc: 'dt-ordering-desc', + none: 'dt-orderable-none', + position: 'sorting_' + }, + processing: { + container: 'dt-processing' + }, + scrolling: { + body: 'dt-scroll-body', + container: 'dt-scroll', + footer: { + self: 'dt-scroll-foot', + inner: 'dt-scroll-footInner' + }, + header: { + self: 'dt-scroll-head', + inner: 'dt-scroll-headInner' + } + }, + search: { + container: 'dt-search', + input: 'dt-input' + }, + table: 'dataTable', + tbody: { + cell: '', + row: '' + }, + thead: { + cell: '', + row: '' + }, + tfoot: { + cell: '', + row: '' + }, + paging: { + active: 'current', + button: 'dt-paging-button', + container: 'dt-paging', + disabled: 'disabled' + } + } ); + + + /* + * It is useful to have variables which are scoped locally so only the + * DataTables functions can access them and they don't leak into global space. + * At the same time these functions are often useful over multiple files in the + * core and API, so we list, or at least document, all variables which are used + * by DataTables as private variables here. This also ensures that there is no + * clashing of variable names and that they can easily referenced for reuse. + */ + + + // Defined else where + // _selector_run + // _selector_opts + // _selector_row_indexes + + var _ext; // DataTable.ext + var _Api; // DataTable.Api + var _api_register; // DataTable.Api.register + var _api_registerPlural; // DataTable.Api.registerPlural + + var _re_dic = {}; + var _re_new_lines = /[\r\n\u2028]/g; + var _re_html = /<([^>]*>)/g; + var _max_str_len = Math.pow(2, 28); + + // This is not strict ISO8601 - Date.parse() is quite lax, although + // implementations differ between browsers. + var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/; + + // Escape regular expression special characters + var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); + + // https://en.wikipedia.org/wiki/Foreign_exchange_market + // - \u20BD - Russian ruble. + // - \u20a9 - South Korean Won + // - \u20BA - Turkish Lira + // - \u20B9 - Indian Rupee + // - R - Brazil (R$) and South Africa + // - fr - Swiss Franc + // - kr - Swedish krona, Norwegian krone and Danish krone + // - \u2009 is thin space and \u202F is narrow no-break space, both used in many + // - Ƀ - Bitcoin + // - Ξ - Ethereum + // standards as thousands separators. + var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi; + + + var _empty = function ( d ) { + return !d || d === true || d === '-' ? true : false; + }; + + + var _intVal = function ( s ) { + var integer = parseInt( s, 10 ); + return !isNaN(integer) && isFinite(s) ? integer : null; + }; + + // Convert from a formatted number with characters other than `.` as the + // decimal place, to a Javascript number + var _numToDecimal = function ( num, decimalPoint ) { + // Cache created regular expressions for speed as this function is called often + if ( ! _re_dic[ decimalPoint ] ) { + _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); + } + return typeof num === 'string' && decimalPoint !== '.' ? + num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : + num; + }; + + + var _isNumber = function ( d, decimalPoint, formatted, allowEmpty ) { + var type = typeof d; + var strType = type === 'string'; + + if ( type === 'number' || type === 'bigint') { + return true; + } + + // If empty return immediately so there must be a number if it is a + // formatted string (this stops the string "k", or "kr", etc being detected + // as a formatted number for currency + if ( allowEmpty && _empty( d ) ) { + return true; + } + + if ( decimalPoint && strType ) { + d = _numToDecimal( d, decimalPoint ); + } + + if ( formatted && strType ) { + d = d.replace( _re_formatted_numeric, '' ); + } + + return !isNaN( parseFloat(d) ) && isFinite( d ); + }; + + + // A string without HTML in it can be considered to be HTML still + var _isHtml = function ( d ) { + return _empty( d ) || typeof d === 'string'; + }; + + // Is a string a number surrounded by HTML? + var _htmlNumeric = function ( d, decimalPoint, formatted, allowEmpty ) { + if ( allowEmpty && _empty( d ) ) { + return true; + } + + // input and select strings mean that this isn't just a number + if (typeof d === 'string' && d.match(/<(input|select)/i)) { + return null; + } + + var html = _isHtml( d ); + return ! html ? + null : + _isNumber( _stripHtml( d ), decimalPoint, formatted, allowEmpty ) ? + true : + null; + }; + + + var _pluck = function ( a, prop, prop2 ) { + var out = []; + var i=0, ien=a.length; + + // Could have the test in the loop for slightly smaller code, but speed + // is essential here + if ( prop2 !== undefined ) { + for ( ; i _max_str_len) { + throw new Error('Exceeded max str len'); + } + + var previous; + + input = input.replace(_re_html, ''); // Complete tags + + // Safety for incomplete script tag - use do / while to ensure that + // we get all instances + do { + previous = input; + input = input.replace(/ - - diff --git a/requirements/base.txt b/requirements/base.txt index e43580b4..a997ab8d 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,9 +7,9 @@ argon2-cffi==23.1.0 # https://github.com/evansd/whitenoise whitenoise==6.7.0 # https://github.com/andymccurdy/redis-py -redis==5.0.7 +redis==5.0.8 # https://github.com/redis/hiredis-py -hiredis==2.3.2 +hiredis==3.0.0 # https://github.com/psycopg/psycopg2 psycopg2-binary==2.9.9 #psycopg2==2.9.9 --no-binary psycopg2 @@ -20,7 +20,7 @@ python-magic==0.4.27 # Django # ------------------------------------------------------------------------------ # https://www.djangoproject.com/ -django==5.0.7 +django==5.1 # https://github.com/django/channels channels[daphne]==4.1.0 # https://github.com/django/daphne @@ -30,13 +30,13 @@ channels_redis==4.2.0 # https://github.com/joke2k/django-environ django-environ==0.11.2 # https://github.com/pennersr/django-allauth -django-allauth[mfa]==0.63.6 +django-allauth[mfa]==64.1.0 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==2.3 # https://github.com/jazzband/django-redis django-redis==5.4.0 # https://gunicorn.org/ -gunicorn==22.0.0 +gunicorn==23.0.0 # Django Ninja @@ -44,7 +44,7 @@ gunicorn==22.0.0 # https://github.com/adamchainz/django-cors-headers django-cors-headers==4.4.0 # https://github.com/vitalik/django-ninja -django-ninja==1.2.2 +django-ninja==1.3.0 # Django tweak # ------------------------------------------------------------------------------ @@ -53,7 +53,7 @@ crispy-bootstrap5==2024.2 # https://github.com/fabiocaccamo/django-colorfield django-colorfield==0.11.0 # https://github.com/mbraak/django-file-form -django-file-form==3.7.0 +django-file-form==3.8.0 # https://github.com/django-guardian/django-guardian django-guardian==2.4.0 # https://github.com/jazzband/django-widget-tweaks @@ -68,24 +68,24 @@ django-extra-settings==0.12.0 # Elasticsearch # ------------------------------------------------------------------------------ # https://github.com/elastic/elasticsearch-py -elasticsearch==8.14.0 +elasticsearch==8.15.0 # https://github.com/elastic/elasticsearch-dsl-py -elasticsearch-dsl==8.14.0 +elasticsearch-dsl==8.15.1 # https://github.com/jurismarches/luqum luqum==0.13.0 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.7.1 +dask==2024.8.1 # https://github.com/dask/distributed -distributed==2024.7.1 +distributed==2024.8.1 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.0.8 # https://github.com/python-lz4/python-lz4 lz4==4.3.3 # https://numpy.org/ -numpy==2.0.1 +numpy==2.1.0 # https://github.com/cloudpipe/cloudpickle cloudpickle==3.0.0 # https://pypi.org/project/toolz/ @@ -106,12 +106,11 @@ plotly==5.23.0 # https://github.com/Viicos/clamdpy clamdpy==0.1.0.post1 # https://github.com/VirusTotal/vt-py -vt-py==0.18.2 +vt-py==0.18.3 # https://github.com/mkorman90/regipy/ -#regipy[full]==4.3.0 -regipy[full] @ git+https://github.com/dadokkio/regipy@6d11c7dc4ef864d13bc84bc23ef2ca80cb0a90f0 +regipy[full]==5.0.0 # http://www.capstone-engine.org/ -capstone==5.0.1 +capstone==5.0.3 # https://github.com/Julian/jsonschema jsonschema==4.23.0 # https://github.com/Legrandin/pycryptodome @@ -137,12 +136,12 @@ python-debian==0.1.49 # https://github.com/srossross/rpmfile rpmfile==2.1.0 # https://github.com/erocarrera/pefile -pefile==2023.2.7 +pefile==2024.8.26 # misp export # ------------------------------------------------------------------------------ # https://github.com/MISP/PyMISP -pymisp==2.4.195 +pymisp==2.4.196 # ldap # ------------------------------------------------------------------------------ diff --git a/requirements/local.txt b/requirements/local.txt index 7473047e..20ff9456 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -3,33 +3,33 @@ # Testing # ------------------------------------------------------------------------------ # https://github.com/python/mypy -mypy==1.11.0 +mypy==1.11.2 # https://github.com/typeddjango/django-stubs -django-stubs==5.0.2 +django-stubs==5.0.4 # https://github.com/pytest-dev/pytest -pytest==8.2.2 +pytest==8.3.2 # https://github.com/Frozenball/pytest-sugar pytest-sugar==1.0.0 # Code quality # ------------------------------------------------------------------------------ # https://github.com/PyCQA/flake8 -flake8==7.0.0 +flake8==7.1.1 # https://github.com/gforcada/flake8-isort flake8-isort==6.1.1 # https://github.com/nedbat/coveragepy -coverage==7.5.4 +coverage==7.6.1 # https://github.com/ambv/black -black==24.4.2 +black==24.8.0 # https://github.com/PyCQA/pylint-django pylint-django==2.5.5 # https://github.com/pre-commit/pre-commit -pre-commit==3.7.1 +pre-commit==3.8.0 # Django # ------------------------------------------------------------------------------ # https://github.com/FactoryBoy/factory_boy -factory-boy==3.3.0 +factory-boy==3.3.1 # https://github.com/jazzband/django-debug-toolbar django-debug-toolbar==4.4.6 # https://github.com/django-extensions/django-extensions From e26acd2aa4ef149f172ac100a727ff3b08e6d846 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 28 Aug 2024 14:50:50 +0200 Subject: [PATCH 66/84] fix datatables filter on bookmarks --- orochi/templates/website/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index 6e7e0e0a..2d5faea2 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -122,7 +122,8 @@
    History Log
    $("#id_selected_indexes").val(selected_indexes); $("#id_selected_plugin").val(selected_plugin); - $("#id_query").val($("#example_filter input").val()); + var table = $('#example').DataTable(); + $("#id_query").val(table.search()); let formData = form.serializeArray(); let obj = {}; From 5a08378af8834d4febb2834ca118089106d6e90a Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 28 Aug 2024 17:33:58 +0200 Subject: [PATCH 67/84] add DEFAULT_FROM_EMAIL settings --- config/settings/local.py | 1 + 1 file changed, 1 insertion(+) diff --git a/config/settings/local.py b/config/settings/local.py index da468de2..fc23409b 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -32,6 +32,7 @@ EMAIL_USE_TLS = env("EMAIL_USE_TLS", default=True) EMAIL_HOST_USER = env("EMAIL_HOST_USER", default=None) EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", default=None) +DEFAULT_FROM_EMAIL = env("DEFAULT_FROM_EMAIL", default=None) # WhiteNoise # ------------------------------------------------------------------------------ From b7a455471fab386fcd720e3403b02bebf3315d06 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 28 Aug 2024 18:06:12 +0200 Subject: [PATCH 68/84] add EMAIL_TIMEOUT settings --- config/settings/local.py | 1 + 1 file changed, 1 insertion(+) diff --git a/config/settings/local.py b/config/settings/local.py index fc23409b..0d42f78e 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -29,6 +29,7 @@ # ------------------------------------------------------------------------------ EMAIL_HOST = env("EMAIL_HOST", default="mailpit") EMAIL_PORT = 1025 +EMAIL_TIMEOUT = env.int("EMAIL_TIMEOUT", default=30) EMAIL_USE_TLS = env("EMAIL_USE_TLS", default=True) EMAIL_HOST_USER = env("EMAIL_HOST_USER", default=None) EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", default=None) From 8914119d2d51000bd415e576f8050163454275cc Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 28 Aug 2024 18:34:06 +0200 Subject: [PATCH 69/84] fix port settings --- .envs/.local/.django | 2 ++ config/settings/local.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.envs/.local/.django b/.envs/.local/.django index e5628db0..598b66ad 100755 --- a/.envs/.local/.django +++ b/.envs/.local/.django @@ -14,6 +14,8 @@ EMAIL_PORT=1025 EMAIL_USE_TLS=False EMAIL_HOST_USER= EMAIL_HOST_PASSWORD= +DEFAULT_FROM_EMAIL= +EMAIL_TIMEOUT=30 # Redis # ------------------------------------------------------------------------------ diff --git a/config/settings/local.py b/config/settings/local.py index 0d42f78e..11475010 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -28,7 +28,7 @@ # EMAIL # ------------------------------------------------------------------------------ EMAIL_HOST = env("EMAIL_HOST", default="mailpit") -EMAIL_PORT = 1025 +EMAIL_PORT = env.int("EMAIL_PORT", default=25) EMAIL_TIMEOUT = env.int("EMAIL_TIMEOUT", default=30) EMAIL_USE_TLS = env("EMAIL_USE_TLS", default=True) EMAIL_HOST_USER = env("EMAIL_HOST_USER", default=None) From 5ca417dc898f8e855b7b40fbbf7722fcd3e85289 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Fri, 30 Aug 2024 11:26:45 +0200 Subject: [PATCH 70/84] email required at signup --- orochi/templates/account/signup.html | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 orochi/templates/account/signup.html diff --git a/orochi/templates/account/signup.html b/orochi/templates/account/signup.html new file mode 100644 index 00000000..77598f1b --- /dev/null +++ b/orochi/templates/account/signup.html @@ -0,0 +1,46 @@ +{% extends "account/base_entrance.html" %} +{% load allauth i18n %} +{% block head_title %} + {% trans "Signup" %} +{% endblock head_title %} +{% block content %} + {% element h1 %} + {% trans "Sign Up" %} + {% endelement %} + {% setvar link %} + + {% endsetvar %} + {% setvar end_link %} + + {% endsetvar %} + {% element p %} + {% blocktranslate %}Already have an account? Then please {{ link }}sign in{{ end_link }}.{% endblocktranslate %} + {% endelement %} + {% if not SOCIALACCOUNT_ONLY %} + {% url 'account_signup' as action_url %} + {% element form form=form method="post" action=action_url tags="entrance,signup" %} + {% slot body %} + {% csrf_token %} + {% element fields form=form unlabeled=True %} + {% endelement %} + {{ redirect_field }} + {% endslot %} + {% slot actions %} + {% element button tags="prominent,signup" type="submit" %} + {% trans "Sign Up" %} + {% endelement %} + {% endslot %} + {% endelement %} + {% endif %} + {% if SOCIALACCOUNT_ENABLED %} + {% include "socialaccount/snippets/login.html" with page_layout="entrance" %} + {% endif %} +{% endblock content %} + +{% block javascript %} +{{ block.super }} + +{% endblock javascript %} From bf72c217c9ac7c98f927d8046f010d898b9a8e33 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Mon, 2 Sep 2024 08:17:54 +0200 Subject: [PATCH 71/84] https support in external env --- config/settings/base.py | 4 ++++ orochi/templates/base.html | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config/settings/base.py b/config/settings/base.py index 5be8adc5..5fe9d043 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -355,3 +355,7 @@ LOCAL_UPLOAD_PATH = env("LOCAL_UPLOAD_PATH") # Regipy plugins REGIPY_PLUGINS = env.list("REGIPY_PLUGINS") + +# HTTPS +SECURE_PROXY_SSL_HEADER = env("HTTP_X_FORWARDED_PROTO", "http") +SECURE_SSL_REDIRECT = env.bool("SECURE_SSL_REDIRECT", False) diff --git a/orochi/templates/base.html b/orochi/templates/base.html index f6c711d1..e20cfd1b 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -202,8 +202,7 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - {% endblock javascript %} + }); + + {% endblock javascript %} diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index 2d5faea2..2dd6ae9e 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -11,7 +11,13 @@ {% endblock %} {% block sidebar %} - + {% include "website/partial_indices.html" %} +
    + +
    + +
    {% endblock sidebar %} @@ -45,23 +52,21 @@ - {% include "website/partial_indices.html" %} -
    - -
    - -
    + dumps + {% if not request.user|has_group:"ReadOnly" %} + + + {% endif %} + + + + {% include "website/partial_indices.html" %} +
    + +
    + +
    {% endblock sidebar %} {% block content%}
    - +
    {% endblock content %} {% block offcanvas %}
    -
    History Log
    - +
    History Log
    +
    -
      - {% for new in news %} -
    • -
      -
      {{new.date|date:"SHORT_DATETIME_FORMAT"}}
      -
      {{new.text|safe}}
      -
      -
    • - {% endfor %} -
    +
      + {% for new in news %} +
    • +
      +
      {{new.date|date:"SHORT_DATETIME_FORMAT"}}
      +
      {{new.text|safe}}
      +
      +
    • + {% endfor %} +
    {% endblock offcanvas %} @@ -75,756 +77,798 @@
    History Log
    {{block.super}} {% endblock javascript %} diff --git a/orochi/templates/website/partial_analysis.html b/orochi/templates/website/partial_analysis.html index a9b290a5..af46af80 100644 --- a/orochi/templates/website/partial_analysis.html +++ b/orochi/templates/website/partial_analysis.html @@ -27,4 +27,11 @@

    {% endfor %} +

    + + {% for col in columns %} + + {% endfor %} + +
    ` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-`` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-`
    {{col}}
    diff --git a/orochi/templates/website/partial_tree.html b/orochi/templates/website/partial_tree.html index c768bc58..2aea8c69 100644 --- a/orochi/templates/website/partial_tree.html +++ b/orochi/templates/website/partial_tree.html @@ -61,7 +61,7 @@

    {{plugin}}

    {% if forloop.first %} { id: "*", title: "{{col}}" }, {% elif forloop.last %} - { id: "color", title: "{{col}}", width: "100px" }, + { id: "orochi_color", title: "{{col}}", width: "100px" }, {% else %} { id: "{{col}}", title: "{{col}}" }, //, sortable: true }, {% endif %} @@ -92,7 +92,7 @@

    {{plugin}}

    for (const col of Object.values(e.renderColInfosById)) { switch (col.id) { - case "color": + case "orochi_color": col.elem.innerHTML = node.data[col.id]? '' : ''; break; default: diff --git a/orochi/website/admin.py b/orochi/website/admin.py index 9462fd73..8e34eb94 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -316,6 +316,7 @@ class PluginAdmin(FileFormAdmin): "vt_check", "clamav_check", "regipy_check", + "maxmind_check", "local", ) search_fields = ("name",) diff --git a/orochi/website/defaults.py b/orochi/website/defaults.py index 7aec62f3..7b3f88fd 100644 --- a/orochi/website/defaults.py +++ b/orochi/website/defaults.py @@ -28,11 +28,9 @@ class OSEnum(models.TextChoices): SERVICE_VIRUSTOTAL = 1 SERVICE_MISP = 2 -SERVICE_MAXMIND = 3 SERVICES = ( (SERVICE_VIRUSTOTAL, "VirusTotal"), (SERVICE_MISP, "MISP"), - (SERVICE_MAXMIND, "MAXMIND"), ) DUMP_STATUS_CREATED = 1 diff --git a/orochi/website/forms.py b/orochi/website/forms.py index b5a62c17..97d728d2 100644 --- a/orochi/website/forms.py +++ b/orochi/website/forms.py @@ -250,6 +250,7 @@ class Meta: "vt_check", "clamav_check", "regipy_check", + "maxmind_check", ] def save(self, commit=True): @@ -292,5 +293,6 @@ class Meta: "vt_check", "clamav_check", "regipy_check", + "maxmind_check", "local", ] diff --git a/orochi/website/migrations/0059_remove_plugin_yara_check_alter_service_name.py b/orochi/website/migrations/0059_remove_plugin_yara_check_alter_service_name.py new file mode 100644 index 00000000..276a550b --- /dev/null +++ b/orochi/website/migrations/0059_remove_plugin_yara_check_alter_service_name.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.1 on 2024-09-23 12:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("website", "0058_remove_result_value_value"), + ] + + operations = [ + migrations.RemoveField( + model_name="plugin", + name="yara_check", + ), + migrations.AlterField( + model_name="service", + name="name", + field=models.PositiveIntegerField( + choices=[(1, "VirusTotal"), (2, "MISP")], unique=True + ), + ), + ] diff --git a/orochi/website/models.py b/orochi/website/models.py index 1d9e7a57..eea05e47 100644 --- a/orochi/website/models.py +++ b/orochi/website/models.py @@ -29,7 +29,6 @@ class Plugin(models.Model): vt_check = models.BooleanField(default=False) clamav_check = models.BooleanField(default=False) regipy_check = models.BooleanField(default=False) - yara_check = models.BooleanField(default=False) maxmind_check = models.BooleanField(default=False) local = models.BooleanField(default=False) local_date = models.DateField(blank=True, null=True) diff --git a/orochi/website/views.py b/orochi/website/views.py index 9855d131..acd61cd6 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -243,7 +243,23 @@ def generate(request): """Sliced data request for analysis ajax datatables request""" if request.META.get("HTTP_X_REQUESTED_WITH") != "XMLHttpRequest": return JsonResponse({"status_code": 405, "error": "Method Not Allowed"}) + + # obtain list of columns ui_columns = request.GET.getlist("columns[]") + + # sorting + sort_column = request.GET.get("order[0][column]") or 0 + sort_column = int(sort_column) + sort_order = request.GET.get("order[0][dir]") or "asc" + + # manage filters on single columns + filters = request.GET.getlist("filters[]") + dict_filters = {} + if filters: + for filter in filters: + name, value = filter.split("___") + dict_filters[name] = value + draw = request.GET.get("draw") if ui_columns == ["Loading"]: @@ -288,18 +304,18 @@ def generate(request): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - dump_index=F("result__dump__index"), - dump_name=F("result__dump__name"), + orochi_dump_index=F("result__dump__index"), + orochi_dump_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), - color=F("result__dump__color"), + orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "dump_index", - "dump_name", + "orochi_dump_index", + "orochi_dump_name", "orochi_os", - "color", + "orochi_color", "orochi_createdAt", "value", ) @@ -307,17 +323,21 @@ def generate(request): total = res.count() + # first filtering main search if search: res = res.filter( Q(value__icontains=search) | Q(orochi_plugin__icontains=search) - | Q(dump_name__icontains=search) + | Q(orochi_dump_name__icontains=search) | Q(orochi_os__icontains=search) | Q(orochi_createdAt__icontains=search) ) - filtered = res.count() - res = res[start : start + length] + # second filtering on each column (dump/plugin) + if filters: + for k, v in dict_filters.items(): + if k.startswith("orochi_"): + res = res.filter(**{f"{k}__icontains": v}) try: _ = Service.objects.get(name=SERVICE_MISP) @@ -330,10 +350,21 @@ def generate(request): # EXPLODE RES for item in res: tmp = {k: item[k] for k in item.keys() - {"value"}} - tmp["color"] = COLOR_TEMPLATE.format(tmp["color"]) + tmp["orochi_color"] = COLOR_TEMPLATE.format(tmp["orochi_color"]) + # third filtering on each column (volatility result) + filtered = False for k, v in item["value"].items(): - tmp[k] = v + if k_filter := dict_filters.get(k): + if v and v.find(k_filter) != -1: + tmp[k] = v + else: + filtered = True + else: + tmp[k] = v + + if filtered: + continue if item["value"].get("down_path"): tmp["actions"] = render_to_string( @@ -353,15 +384,21 @@ def generate(request): }, ) - item.update({"color": COLOR_TEMPLATE.format(item["color"])}) list_row = [] for column in ui_columns: if column in tmp: list_row.append(tmp[column]) else: list_row.append("-") + data.append(list_row) + filtered = len(data) + + data = sorted(data, key=lambda d: d[sort_column], reverse=sort_order == "asc") + + data = data[start : start + length] + return JsonResponse( { "draw": draw, @@ -453,8 +490,8 @@ def analysis(request): # GET COLUMNS FROM ELASTIC columns = ( [ - "color", - "dump_name", + "orochi_color", + "orochi_dump_name", "orochi_plugin", "orochi_os", "orochi_createdAt", @@ -517,7 +554,7 @@ def analysis(request): not in SYSTEM_COLUMNS + [PLUGIN_WITH_CHILDREN[plugin.name.lower()], "__children"] ] - + ["dump_name", "color"] + + ["orochi_dump_name", "orochi_color"] ) # If tree we will render tree and get data dynamically @@ -555,16 +592,16 @@ def tree(request): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - dump_name=F("result__dump__name"), + orochi_dump_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), - color=F("result__dump__color"), + orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "dump_name", + "orochi_dump_name", "orochi_os", - "color", + "orochi_color", "orochi_createdAt", "value", ) @@ -575,7 +612,7 @@ def tree(request): for k, v in item["value"].items(): tmp[k] = v tmp = change_keys(tmp, title) - tmp["color"] = tmp["color"] + tmp["orochi_color"] = tmp["orochi_color"] data.append(tmp) return JsonResponse(data, safe=False) @@ -727,16 +764,16 @@ def diff_view(request, index_a, index_b, plugin): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - dump_name=F("result__dump__name"), + orochi_dump_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), - color=F("result__dump__color"), + orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "dump_name", + "orochi_dump_name", "orochi_os", - "color", + "orochi_color", "orochi_createdAt", "value", ) @@ -754,16 +791,16 @@ def diff_view(request, index_a, index_b, plugin): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - dump_name=F("result__dump__name"), + orochi_dump_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), - color=F("result__dump__color"), + orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "dump_name", + "orochi_dump_name", "orochi_os", - "color", + "orochi_color", "orochi_createdAt", "value", ) From 946253a7230c0bd4b772685d06117badcda42328 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 25 Sep 2024 15:13:39 +0200 Subject: [PATCH 82/84] use browser history --- orochi/templates/website/index.html | 39 +++++++++++++++++++++-------- orochi/utils/timeliner.py | 17 ++++++------- orochi/website/admin.py | 1 - orochi/website/views.py | 1 + 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index 98ec38c8..08f644e3 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -89,6 +89,15 @@
    History Log
    var selected_indexes = {{ selected_indexes| safe }}; var selected_plugin = {% if not selected_plugin %}null{% else %} "{{selected_plugin}}"{% endif %}; var selected_query = {% if not selected_query %}null{% else %} "{{selected_query}}"{% endif %}; + + window.onpopstate = function(event) { + if(event && event.state) { + selected_plugin = event.state.selected_plugin; + selected_indexes = event.state.selected_indexes; + update_sidebar(); + } + } + if (selected_plugin && selected_indexes.length > 0) { selected_indexes.forEach(element => { var label = $('#index-list li label').filter('[data-index="' + element + '"]'); @@ -103,7 +112,6 @@
    History Log
    }); update_sidebar(); } - window.history.pushState("", "", '/'); // ADD BOOKMARK FORM $(document).on("click", "#bookmark", function (e) { @@ -150,7 +158,6 @@
    History Log
    type: form.attr("method"), dataType: 'json', success: function (data) { - $.toast({ title: 'Bookmark saved!', content: 'Bookmark saved.', @@ -257,9 +264,15 @@
    History Log
    // UPDATE MAIN STAGE AFTER INDEX, PLUGIN CHANGE function update_main_stage() { if (selected_plugin == null || selected_indexes.length == 0) { + window.history.pushState({selected_plugin: null, selected_indexes: null}, "", "/"); $('#main_stage').html(''); } else { + window.history.pushState( + {selected_plugin: selected_plugin, selected_indexes: selected_indexes}, + "", + "/indexes/" + selected_indexes.join(",") + "/plugin/" + selected_plugin + ); $.get("{% url 'website:analysis' %}", { 'indexes': selected_indexes, 'plugin': selected_plugin }) .done(function (data) { @@ -380,17 +393,20 @@
    History Log
    if (indexes.length > 0) { var template = Handlebars.templates.plugins; var url = "{% url 'api:dumps_plugins' pks=111111111122222222223333333333444444 %}".replace(/111111111122222222223333333333444444/, indexes.join(",")); - $.ajax({ url: url, method: 'get', dataType: 'json', success: function (data) { $("#list_plugin").append(template(data)) + if(selected_plugin){ + var label = $('#list_plugin li label').filter('[data-plugin="' + selected_plugin + '"]'); + checkbox = $(":radio", label.parent()); + checkbox.prop('checked', true); + } } }); } - } selected_indexes = indexes; update_main_stage(); @@ -547,6 +563,7 @@
    History Log
    }); }); + // OPEN/CLOSE FOLDER TO HIDE ELEMENTS INSIDE $(document).on("change", "#id_local_folder", function () { var value = $(this).val(); if (value != "") { @@ -576,7 +593,8 @@
    History Log
    if (data.form_is_valid) { $("#index-list").html(data.dumps); $("#modal-update").modal('hide'); - update_main_stage(); + selected_plugin = null; + update_sidebar(); } else { $("#modal-update .modal-content").html(data.html_form); $("#create_loading").hide(); @@ -649,7 +667,6 @@
    History Log
    }); }); - // RESTART INDEX FORM SUBMIT $(document).on("click", ".restart-index", function (e) { var btn = $(this); @@ -691,7 +708,8 @@
    History Log
    type: 'get', dataType: 'json', success: function (data) { - console.log(data); + selected_plugin = null; + update_sidebar(); } }); }); @@ -731,7 +749,8 @@
    History Log
    if (data.form_is_valid) { $("#index-list").html(data.dumps); $("#modal-update").modal('hide'); - update_main_stage(); + selected_plugin = null; + update_sidebar(); } else { $("#modal-update .modal-content").html(data.html_form); } @@ -792,7 +811,8 @@
    History Log
    if (data.form_is_valid) { $("#index-list").html(data.dumps); $("#modal-update").modal('hide'); - update_main_stage(); + selected_plugin = null; + update_sidebar(); } else { $("#modal-update .modal-content").html(data.html_form); } @@ -819,7 +839,6 @@
    History Log
    }); selected_plugin = null; update_sidebar(); - update_main_stage(); $.toast({ title: 'Index delete!', content: 'Index has been deleted successfully.', diff --git a/orochi/utils/timeliner.py b/orochi/utils/timeliner.py index c1a4bb45..0092a294 100644 --- a/orochi/utils/timeliner.py +++ b/orochi/utils/timeliner.py @@ -2,7 +2,6 @@ import pandas as pd import plotly.express as px -from django.views.generic.base import TemplateView def parse_body_line(line): @@ -53,15 +52,13 @@ def clean_bodywork(file_path): legend_title="Plugin", xaxis=dict( rangeselector=dict( - buttons=list( - [ - dict(count=1, label="1m", step="month", stepmode="backward"), - dict(count=6, label="6m", step="month", stepmode="backward"), - dict(count=1, label="YTD", step="year", stepmode="todate"), - dict(count=1, label="1y", step="year", stepmode="backward"), - dict(step="all"), - ] - ) + buttons=[ + dict(count=1, label="1m", step="month", stepmode="backward"), + dict(count=6, label="6m", step="month", stepmode="backward"), + dict(count=1, label="YTD", step="year", stepmode="todate"), + dict(count=1, label="1y", step="year", stepmode="backward"), + dict(step="all"), + ] ), rangeslider=dict(visible=True), type="date", diff --git a/orochi/website/admin.py b/orochi/website/admin.py index 8e34eb94..65261344 100644 --- a/orochi/website/admin.py +++ b/orochi/website/admin.py @@ -16,7 +16,6 @@ from guardian.shortcuts import assign_perm, get_perms, remove_perm from import_export import fields, resources from import_export.admin import ExportActionMixin, ImportExportModelAdmin -from import_export.mixins import BaseImportExportMixin from import_export.widgets import ForeignKeyWidget from orochi.website.defaults import RESULT diff --git a/orochi/website/views.py b/orochi/website/views.py index acd61cd6..bb7135ce 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -950,6 +950,7 @@ def bookmarks(request, indexes, plugin, query=None): "selected_indexes": indexes, "selected_plugin": plugin, "selected_query": query, + "readonly": is_not_readonly(request.user), } return TemplateResponse(request, "website/index.html", context) From 17e782f39ffb76e1b74e6f88351dfbc9c96b8712 Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 25 Sep 2024 15:24:42 +0200 Subject: [PATCH 83/84] fix diff_view path --- orochi/templates/website/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orochi/templates/website/index.html b/orochi/templates/website/index.html index 08f644e3..779bc7dc 100644 --- a/orochi/templates/website/index.html +++ b/orochi/templates/website/index.html @@ -466,7 +466,7 @@
    History Log
    }).get(); var plugin = $(this).data('plugin'); if (indexes.length == 2) { - var url = `diff_view/${indexes[0]}/${indexes[1]}/${plugin}`; + var url = `/diff_view/${indexes[0]}/${indexes[1]}/${plugin}`; window.open(url, "_blank"); } }); From 16b9f81a9423f4069264499d6f67c76c0aaa85db Mon Sep 17 00:00:00 2001 From: Davide Arcuri Date: Wed, 16 Oct 2024 11:56:31 +0200 Subject: [PATCH 84/84] fix new menu, update libs --- .pre-commit-config.yaml | 2 +- compose/local/dask/Dockerfile | 4 ++-- compose/local/django/Dockerfile | 4 ++-- orochi/api/models.py | 2 +- orochi/templates/base.html | 2 +- orochi/website/views.py | 28 +++++++++++++++------------- requirements/base.txt | 30 +++++++++++++++--------------- requirements/local.txt | 12 ++++++------ 8 files changed, 43 insertions(+), 41 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8758d40d..500efb2c 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-yaml - repo: https://github.com/psf/black - rev: 24.8.0 + rev: 24.10.0 hooks: - id: black diff --git a/compose/local/dask/Dockerfile b/compose/local/dask/Dockerfile index 0c1b4bd3..57aacfec 100644 --- a/compose/local/dask/Dockerfile +++ b/compose/local/dask/Dockerfile @@ -1,4 +1,4 @@ -FROM daskdev/dask:2024.9.0-py3.12 +FROM daskdev/dask:2024.9.1-py3.12 ENV DEBIAN_FRONTEND noninteractive ARG local_folder=/uploads @@ -27,7 +27,7 @@ RUN freshclam # Workers should have similar reqs as django WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.4.12 -e git+https://github.com/dadokkio/volatility3.git@bb6ab45363b834576cf392e5f438a9a5f605610f#egg=volatility3 \ +RUN pip install uv==0.4.21 -e git+https://github.com/dadokkio/volatility3.git@7b0cb4facd1e1714a36793a27c0570461a3f02a1#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/dask/prepare.sh /usr/bin/prepare.sh diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile index 26ac4377..ffc063bc 100644 --- a/compose/local/django/Dockerfile +++ b/compose/local/django/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.5-slim-bookworm as common-base +FROM python:3.12.6-slim-bookworm as common-base ENV DJANGO_SETTINGS_MODULE config.settings.local ENV PYTHONUNBUFFERED 1 @@ -44,7 +44,7 @@ RUN /usr/local/go/bin/go build FROM common-base WORKDIR / COPY ./requirements /requirements -RUN pip install uv==0.4.12 -e git+https://github.com/dadokkio/volatility3.git@bb6ab45363b834576cf392e5f438a9a5f605610f#egg=volatility3 \ +RUN pip install uv==0.4.21 -e git+https://github.com/dadokkio/volatility3.git@7b0cb4facd1e1714a36793a27c0570461a3f02a1#egg=volatility3 \ && uv pip install --no-cache --system -r /requirements/base.txt COPY ./compose/local/__init__.py /src/volatility3/volatility3/framework/constants/__init__.py diff --git a/orochi/api/models.py b/orochi/api/models.py index 312d7ce1..622e0acf 100644 --- a/orochi/api/models.py +++ b/orochi/api/models.py @@ -210,7 +210,7 @@ class Meta: ################################################### class ResultSmallOutSchema(Schema): name: str = Field(..., alias="plugin__name") - comment: str = Field(..., alias="plugin__comment") + comment: Optional[str] = Field(..., alias="plugin__comment") ################################################### diff --git a/orochi/templates/base.html b/orochi/templates/base.html index 29130d53..e07de37b 100644 --- a/orochi/templates/base.html +++ b/orochi/templates/base.html @@ -29,7 +29,7 @@
    - {% if dumps %} + {% if main_page %} {% trans "Main" %} diff --git a/orochi/website/views.py b/orochi/website/views.py index bb7135ce..2ca4e19e 100644 --- a/orochi/website/views.py +++ b/orochi/website/views.py @@ -304,16 +304,16 @@ def generate(request): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - orochi_dump_index=F("result__dump__index"), - orochi_dump_name=F("result__dump__name"), + orochi_index=F("result__dump__index"), + orochi_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "orochi_dump_index", - "orochi_dump_name", + "orochi_index", + "orochi_name", "orochi_os", "orochi_color", "orochi_createdAt", @@ -328,7 +328,7 @@ def generate(request): res = res.filter( Q(value__icontains=search) | Q(orochi_plugin__icontains=search) - | Q(orochi_dump_name__icontains=search) + | Q(orochi_name__icontains=search) | Q(orochi_os__icontains=search) | Q(orochi_createdAt__icontains=search) ) @@ -491,7 +491,7 @@ def analysis(request): columns = ( [ "orochi_color", - "orochi_dump_name", + "orochi_name", "orochi_plugin", "orochi_os", "orochi_createdAt", @@ -554,7 +554,7 @@ def analysis(request): not in SYSTEM_COLUMNS + [PLUGIN_WITH_CHILDREN[plugin.name.lower()], "__children"] ] - + ["orochi_dump_name", "orochi_color"] + + ["orochi_name", "orochi_color"] ) # If tree we will render tree and get data dynamically @@ -592,14 +592,14 @@ def tree(request): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - orochi_dump_name=F("result__dump__name"), + orochi_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "orochi_dump_name", + "orochi_name", "orochi_os", "orochi_color", "orochi_createdAt", @@ -764,14 +764,14 @@ def diff_view(request, index_a, index_b, plugin): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - orochi_dump_name=F("result__dump__name"), + orochi_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "orochi_dump_name", + "orochi_name", "orochi_os", "orochi_color", "orochi_createdAt", @@ -791,14 +791,14 @@ def diff_view(request, index_a, index_b, plugin): .filter(result__result=RESULT_STATUS_SUCCESS) .annotate( orochi_plugin=F("result__plugin__name"), - orochi_dump_name=F("result__dump__name"), + orochi_name=F("result__dump__name"), orochi_os=F("result__dump__operating_system"), orochi_color=F("result__dump__color"), orochi_createdAt=F("result__updated_at"), ) .values( "orochi_plugin", - "orochi_dump_name", + "orochi_name", "orochi_os", "orochi_color", "orochi_createdAt", @@ -947,6 +947,7 @@ def bookmarks(request, indexes, plugin, query=None): "dumps": get_objects_for_user(request.user, "website.can_see") .values_list(*INDEX_VALUES_LIST) .order_by("folder__name", "name"), + "main_page": True, "selected_indexes": indexes, "selected_plugin": plugin, "selected_query": query, @@ -992,6 +993,7 @@ def index(request): "dumps": get_objects_for_user(request.user, "website.can_see") .values_list(*INDEX_VALUES_LIST) .order_by("folder__name", "name"), + "main_page": True, "selected_indexes": [], "selected_plugin": None, "selected_query": None, diff --git a/requirements/base.txt b/requirements/base.txt index b65dd001..db5ce7dc 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,7 +7,7 @@ argon2-cffi==23.1.0 # https://github.com/evansd/whitenoise whitenoise==6.7.0 # https://github.com/andymccurdy/redis-py -redis==5.0.8 +redis==5.1.1 # https://github.com/redis/hiredis-py hiredis==3.0.0 # https://github.com/psycopg/psycopg2 @@ -20,7 +20,7 @@ python-magic==0.4.27 # Django # ------------------------------------------------------------------------------ # https://www.djangoproject.com/ -django==5.1.1 +django==5.1.2 # https://github.com/django/channels channels[daphne]==4.1.0 # https://github.com/django/daphne @@ -30,7 +30,7 @@ channels_redis==4.2.0 # https://github.com/joke2k/django-environ django-environ==0.11.2 # https://github.com/pennersr/django-allauth -django-allauth[mfa]==64.2.1 +django-allauth[mfa]==65.0.2 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==2.3 # https://github.com/jazzband/django-redis @@ -43,14 +43,14 @@ django-import-export==4.1.1 # Django Ninja # ------------------------------------------------------------------------------ # https://github.com/adamchainz/django-cors-headers -django-cors-headers==4.4.0 +django-cors-headers==4.5.0 # https://github.com/vitalik/django-ninja django-ninja==1.3.0 # Django tweak # ------------------------------------------------------------------------------ # https://github.com/django-crispy-forms/crispy-bootstrap5 -crispy-bootstrap5==2024.2 +crispy-bootstrap5==2024.10 # https://github.com/fabiocaccamo/django-colorfield django-colorfield==0.11.0 # https://github.com/mbraak/django-file-form @@ -71,23 +71,23 @@ django-json-widget==2.0.1 # Dask & co # ------------------------------------------------------------------------------ # https://github.com/dask/dask -dask==2024.9.0 +dask==2024.9.1 # https://github.com/dask/distributed -distributed==2024.9.0 +distributed==2024.9.1 # https://msgpack.org/ TO BE ALIGNED WITH SCHEDULER msgpack==1.1.0 # https://github.com/python-lz4/python-lz4 lz4==4.3.3 # https://numpy.org/ -numpy==2.1.1 +numpy==2.1.2 # https://github.com/cloudpipe/cloudpickle -cloudpickle==3.0.0 +cloudpickle==3.1.0 # https://pypi.org/project/toolz/ -toolz==0.12.1 +toolz==1.0.0 # https://pypi.org/project/tornado/ tornado==6.4.1 # https://pandas.pydata.org/ -pandas==2.2.2 +pandas==2.2.3 # Plotting # ------------------------------------------------------------------------------ @@ -108,7 +108,7 @@ capstone==5.0.3 # https://github.com/Julian/jsonschema jsonschema==4.23.0 # https://github.com/Legrandin/pycryptodome -pycryptodome==3.20.0 +pycryptodome==3.21.0 # https://github.com/maxmind/GeoIP2-python geoip2==4.8.0 @@ -119,7 +119,7 @@ GitPython==3.1.43 # https://github.com/frostming/marko marko==2.1.2 # https://github.com/VirusTotal/yara-x -yara_x==0.8.0 +yara_x==0.9.0 # symbols dwarf # ------------------------------------------------------------------------------ @@ -135,10 +135,10 @@ pefile==2024.8.26 # misp export # ------------------------------------------------------------------------------ # https://github.com/MISP/PyMISP -pymisp==2.4.198 +pymisp==2.5.0 # ldap # ------------------------------------------------------------------------------ # https://github.com/python-ldap/python-ldap python-ldap==3.4.4 -django-auth-ldap==4.8.0 +django-auth-ldap==5.0.0 diff --git a/requirements/local.txt b/requirements/local.txt index 73fa9bef..556064f0 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -3,9 +3,9 @@ # Testing # ------------------------------------------------------------------------------ # https://github.com/python/mypy -mypy==1.11.2 +mypy==1.12.0 # https://github.com/typeddjango/django-stubs -django-stubs==5.0.4 +django-stubs==5.1.0 # https://github.com/pytest-dev/pytest pytest==8.3.3 # https://github.com/Frozenball/pytest-sugar @@ -18,13 +18,13 @@ flake8==7.1.1 # https://github.com/gforcada/flake8-isort flake8-isort==6.1.1 # https://github.com/nedbat/coveragepy -coverage==7.6.1 +coverage==7.6.3 # https://github.com/ambv/black -black==24.8.0 +black==24.10.0 # https://github.com/PyCQA/pylint-django -pylint-django==2.5.5 +pylint-django==2.6.1 # https://github.com/pre-commit/pre-commit -pre-commit==3.8.0 +pre-commit==4.0.1 # Django # ------------------------------------------------------------------------------