From 5b57f75b4e0d8232a357ab2d43ee941efb488636 Mon Sep 17 00:00:00 2001 From: Kenneth SOARES Date: Wed, 9 Apr 2025 17:33:34 +0200 Subject: [PATCH 01/14] custom django command for promo logos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit added path vailidity verification and IOError handling added option to overwrite existing logo and force flag improved uppon suggestions mistake correction fixed string conversion bugs and logical error corrected path conversion f better error handling and corrections ajout d'une section de documentation pour la feature copié coller fixed documentation bullet points added resampling clean up error handling removed useless IOError --- core/management/commands/add_promo_logo.py | 41 ++++++++++++++++++++++ docs/howto/logo.md | 9 +++++ 2 files changed, 50 insertions(+) create mode 100644 core/management/commands/add_promo_logo.py diff --git a/core/management/commands/add_promo_logo.py b/core/management/commands/add_promo_logo.py new file mode 100644 index 00000000..7627af90 --- /dev/null +++ b/core/management/commands/add_promo_logo.py @@ -0,0 +1,41 @@ +import pathlib + +from django.apps import apps +from django.core.management.base import BaseCommand +from PIL import Image, UnidentifiedImageError + + +class Command(BaseCommand): + def add_arguments(self, parser): + parser.add_argument("number", type=int) + parser.add_argument("path", type=pathlib.Path) + parser.add_argument("-f", "--force", action="store_true") + + def handle(self, number: int, path: pathlib.Path, force: int, *args, **options): + if not path.exists() or path.is_dir(): + self.stderr.write(f"{path} is not a file or does not exist") + return + + dest_path = ( + pathlib.Path(apps.get_app_config("core").path) + / "static" + / "core" + / "img" + / f"promo_{number}.png" + ) + + if dest_path.exists() and not force: + over = input("File already exists, do you want to overwrite it? (y/N):") + if over.lower() != "y": + self.stdout.write("exiting") + return + try: + im = Image.open(path) + im.resize((120, 120), resample=Image.Resampling.LANCZOS).save( + dest_path, format="PNG" + ) + self.stdout.write( + f"Promo logo moved and resized successfully at {dest_path}" + ) + except UnidentifiedImageError: + self.stderr.write("image cannot be opened and identified.") diff --git a/docs/howto/logo.md b/docs/howto/logo.md index 6db5b289..d292db0e 100644 --- a/docs/howto/logo.md +++ b/docs/howto/logo.md @@ -12,6 +12,15 @@ nouveau logo d'une promo. C'est un processus manuel. de faire cette opération manuellement, ça prend quelques minutes et on est certain de la qualité à la fin. +### avec une commande django +```bash +./manage.py add_promo_logo numero_de_promo chemin_dacces_du_logo +``` +options: + +* `--force/-f` pour automatiquement écraser les logos de promo avec le même nom. + +### manuellement Les logos de promo sont à manuellement ajouter dans le projet. Ils se situent dans le dossier `core/static/core/img/`. From ae5165af19afeff3c21da6efc9be67f3c6d73558 Mon Sep 17 00:00:00 2001 From: Sli Date: Mon, 7 Jul 2025 11:49:45 +0200 Subject: [PATCH 02/14] fix footer alignment on small screens --- core/static/core/footer.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/static/core/footer.scss b/core/static/core/footer.scss index 52cd317d..aa2e048f 100644 --- a/core/static/core/footer.scss +++ b/core/static/core/footer.scss @@ -2,6 +2,10 @@ @import "devices"; footer.bottom-links { + >section>a { + text-align: center; + } + @media (max-width: $small-devices) { margin-top: 0.6em; padding: 1.25em; From c016dbc8bc48ef2c627db5292b823a2fee5c557d Mon Sep 17 00:00:00 2001 From: Sli Date: Fri, 22 Aug 2025 10:36:57 +0200 Subject: [PATCH 03/14] Fix auto basket cleaning after refilling account --- eboutic/views.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/eboutic/views.py b/eboutic/views.py index 869fe7e9..8a196fcc 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -48,7 +48,14 @@ from django_countries.fields import Country from core.auth.mixins import CanViewMixin, IsSubscriberMixin from core.views.mixins import FragmentMixin, UseFragmentsMixin from counter.forms import BaseBasketForm, BillingInfoForm, ProductForm -from counter.models import BillingInfo, Customer, Product, Selling, get_eboutic +from counter.models import ( + BillingInfo, + Customer, + Product, + Refilling, + Selling, + get_eboutic, +) from eboutic.models import ( Basket, BasketItem, @@ -120,17 +127,39 @@ class EbouticMainView(LoginRequiredMixin, FormView): def customer(self) -> Customer: return Customer.get_or_create(self.request.user)[0] + def get_purchase_timestamp( + self, purchase: Selling | Refilling | None + ) -> int | None: + if purchase is None: + return None + return int(purchase.date.timestamp() * 1000) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["products"] = self.products context["customer_amount"] = self.request.user.account_balance - last_purchase: Selling | None = ( + + last_buying: Selling | None = ( self.customer.buyings.filter(counter__type="EBOUTIC") .order_by("-date") .first() ) + last_refilling: Refilling | None = ( + self.customer.refillings.filter(counter__type="EBOUTIC") + .order_by("-date") + .first() + ) + purchase_times = [ + timestamp + for timestamp in [ + self.get_purchase_timestamp(last_buying), + self.get_purchase_timestamp(last_refilling), + ] + if timestamp is not None + ] + context["last_purchase_time"] = ( - int(last_purchase.date.timestamp() * 1000) if last_purchase else "null" + max(*purchase_times) if len(purchase_times) > 0 else "null" ) return context From f44fe724233c1c8ce08cd8e6caffa090533bcfe7 Mon Sep 17 00:00:00 2001 From: Sli Date: Sat, 23 Aug 2025 12:55:02 +0200 Subject: [PATCH 04/14] Get customer last purchases in one request --- eboutic/views.py | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/eboutic/views.py b/eboutic/views.py index 8a196fcc..f4762534 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -34,6 +34,7 @@ from django.contrib.auth.mixins import ( from django.contrib.messages.views import SuccessMessageMixin from django.core.exceptions import SuspiciousOperation, ValidationError from django.db import DatabaseError, transaction +from django.db.models import Subquery from django.db.models.fields import forms from django.db.utils import cached_property from django.http import HttpResponse @@ -127,39 +128,38 @@ class EbouticMainView(LoginRequiredMixin, FormView): def customer(self) -> Customer: return Customer.get_or_create(self.request.user)[0] - def get_purchase_timestamp( - self, purchase: Selling | Refilling | None - ) -> int | None: - if purchase is None: - return None - return int(purchase.date.timestamp() * 1000) - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["products"] = self.products context["customer_amount"] = self.request.user.account_balance - last_buying: Selling | None = ( - self.customer.buyings.filter(counter__type="EBOUTIC") - .order_by("-date") - .first() - ) - last_refilling: Refilling | None = ( - self.customer.refillings.filter(counter__type="EBOUTIC") - .order_by("-date") - .first() - ) purchase_times = [ - timestamp - for timestamp in [ - self.get_purchase_timestamp(last_buying), - self.get_purchase_timestamp(last_refilling), - ] - if timestamp is not None + int(purchase.timestamp() * 1000) + for purchase in ( + Customer.objects.filter(pk=self.customer.pk) + .annotate( + last_refill=Subquery( + Refilling.objects.filter( + counter__type="EBOUTIC", customer_id=self.customer.pk + ) + .order_by("-date") + .values("date")[:1] + ), + last_purchase=Subquery( + Selling.objects.filter( + counter__type="EBOUTIC", customer_id=self.customer.pk + ) + .order_by("-date") + .values("date")[:1] + ), + ) + .values("last_refill", "last_purchase") + )[0].values() + if purchase is not None ] context["last_purchase_time"] = ( - max(*purchase_times) if len(purchase_times) > 0 else "null" + max(purchase_times) if len(purchase_times) > 0 else "null" ) return context From 0bc18be75efa731976dbca878d17e9116b9c4a56 Mon Sep 17 00:00:00 2001 From: Sli Date: Sat, 23 Aug 2025 15:16:57 +0200 Subject: [PATCH 05/14] Add basket cleaning tests --- eboutic/tests/test_basket.py | 99 +++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/eboutic/tests/test_basket.py b/eboutic/tests/test_basket.py index 60081102..8ea45dbd 100644 --- a/eboutic/tests/test_basket.py +++ b/eboutic/tests/test_basket.py @@ -1,3 +1,5 @@ +from datetime import datetime + import pytest from django.http import HttpResponse from django.test import TestCase @@ -7,10 +9,18 @@ from django.utils.timezone import localdate from model_bakery import baker from pytest_django.asserts import assertRedirects +from club.models import Club from core.baker_recipes import subscriber_user from core.models import Group, User from counter.baker_recipes import product_recipe -from counter.models import Counter, ProductType, get_eboutic +from counter.models import ( + Counter, + Customer, + ProductType, + Refilling, + Selling, + get_eboutic, +) from counter.tests.test_counter import BasketItem from eboutic.models import Basket @@ -24,6 +34,93 @@ def test_get_eboutic(): assert Counter.objects.get(name="Eboutic") == get_eboutic() +@pytest.mark.django_db +def test_eboutic_access_unregistered(client: Client): + eboutic_url = reverse("eboutic:main") + assertRedirects( + client.get(eboutic_url), reverse("core:login", query={"next": eboutic_url}) + ) + + +@pytest.mark.django_db +def test_eboutic_access_new_customer(client: Client): + user = baker.make(User) + assert Customer.objects.filter(user=user).first() is None + + client.force_login(user) + + assert client.get(reverse("eboutic:main")).status_code == 200 + assert Customer.objects.filter(user=user).first() + + +@pytest.mark.django_db +def test_eboutic_access_old_customer(client: Client): + user = baker.make(User) + customer = Customer.get_or_create(user)[0] + + client.force_login(user) + + assert client.get(reverse("eboutic:main")).status_code == 200 + assert Customer.objects.filter(user=user).first() == customer + + +@pytest.mark.django_db +@pytest.mark.parametrize( + ("sellings", "refillings", "expected"), + ( + ([], [], None), + ([datetime(2025, 3, 7, 1, 2, 3)], [], datetime(2025, 3, 7, 1, 2, 3)), + ([], [datetime(2025, 3, 7, 1, 2, 3)], datetime(2025, 3, 7, 1, 2, 3)), + ( + [datetime(2025, 2, 7, 1, 2, 3)], + [datetime(2025, 3, 7, 1, 2, 3)], + datetime(2025, 3, 7, 1, 2, 3), + ), + ( + [datetime(2025, 3, 7, 1, 2, 3)], + [datetime(2025, 2, 7, 1, 2, 3)], + datetime(2025, 3, 7, 1, 2, 3), + ), + ( + [datetime(2025, 3, 7, 1, 2, 3), datetime(2025, 2, 7, 1, 2, 3)], + [datetime(2025, 3, 7, 1, 2, 3)], + datetime(2025, 3, 7, 1, 2, 3), + ), + ), +) +def test_eboutic_basket_expiry( + client: Client, + sellings: list[datetime], + refillings: list[datetime], + expected: datetime | None, +): + eboutic = get_eboutic() + + user = baker.make(User) + customer = Customer.get_or_create(user)[0] + + client.force_login(user) + + for date in sellings: + baker.make( + Selling, + customer=customer, + counter=eboutic, + club=baker.make(Club), + seller=user, + date=date, + is_validated=True, # Ignore not enough money warnings + ) + + for date in refillings: + baker.make(Refilling, customer=customer, counter=eboutic, date=date) + + assert ( + f'x-data="basket({int(expected.timestamp() * 1000) if expected else "null"})"' + in client.get(reverse("eboutic:main")).text + ) + + class TestEboutic(TestCase): @classmethod def setUpTestData(cls): From cbf2678f6d3437271259e1d3f73546cbe79e1171 Mon Sep 17 00:00:00 2001 From: Sli Date: Sat, 23 Aug 2025 15:30:59 +0200 Subject: [PATCH 06/14] Remove euroks partnership --- eboutic/templates/eboutic/eboutic_main.jinja | 50 ----------------- eboutic/urls.py | 2 - eboutic/views.py | 8 +-- locale/fr/LC_MESSAGES/django.po | 59 ++++---------------- locale/fr/LC_MESSAGES/djangojs.po | 4 +- 5 files changed, 15 insertions(+), 108 deletions(-) diff --git a/eboutic/templates/eboutic/eboutic_main.jinja b/eboutic/templates/eboutic/eboutic_main.jinja index db5bf7ed..18ece465 100644 --- a/eboutic/templates/eboutic/eboutic_main.jinja +++ b/eboutic/templates/eboutic/eboutic_main.jinja @@ -120,56 +120,6 @@ {% endif %} -
-
-

{% trans %}Eurockéennes 2025 partnership{% endtrans %}

- {% if user.is_subscribed %} -
-

- {% trans trimmed %} - Our partner uses Weezevent to sell tickets. - Weezevent may collect user info according to - its own privacy policy. - By clicking the accept button you consent to - their terms of services. - {% endtrans %} -

- - {% trans %}Privacy policy{% endtrans %} - - -
- {% else %} -

- {%- trans trimmed %} - You must be subscribed to benefit from the partnership with the Eurockéennes. - {% endtrans -%} -

-

- {%- trans trimmed %} - This partnership offers a discount of up to 33% - on tickets for Friday, Saturday and Sunday, - as well as the 3-day package from Friday to Sunday. - {% endtrans -%} -

- {% endif %} -
-
{% for priority_groups in products|groupby('order') %} {% for category, items in priority_groups.list|groupby('category') %} {% if items|count > 0 %} diff --git a/eboutic/urls.py b/eboutic/urls.py index 54afd428..732dac2f 100644 --- a/eboutic/urls.py +++ b/eboutic/urls.py @@ -31,7 +31,6 @@ from eboutic.views import ( EbouticMainView, EbouticPayWithSith, EtransactionAutoAnswer, - EurokPartnerFragment, payment_result, ) @@ -46,7 +45,6 @@ urlpatterns = [ "pay/sith/", EbouticPayWithSith.as_view(), name="pay_with_sith" ), path("pay//", payment_result, name="payment_result"), - path("eurok/", EurokPartnerFragment.as_view(), name="eurok"), path( "et_autoanswer", EtransactionAutoAnswer.as_view(), diff --git a/eboutic/views.py b/eboutic/views.py index 869fe7e9..ec937e9b 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -41,11 +41,11 @@ from django.shortcuts import redirect, render from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.decorators.http import require_GET -from django.views.generic import DetailView, FormView, TemplateView, UpdateView, View +from django.views.generic import DetailView, FormView, UpdateView, View from django.views.generic.edit import SingleObjectMixin from django_countries.fields import Country -from core.auth.mixins import CanViewMixin, IsSubscriberMixin +from core.auth.mixins import CanViewMixin from core.views.mixins import FragmentMixin, UseFragmentsMixin from counter.forms import BaseBasketForm, BillingInfoForm, ProductForm from counter.models import BillingInfo, Customer, Product, Selling, get_eboutic @@ -142,10 +142,6 @@ def payment_result(request, result: str) -> HttpResponse: return render(request, "eboutic/eboutic_payment_result.jinja", context) -class EurokPartnerFragment(IsSubscriberMixin, TemplateView): - template_name = "eboutic/eurok_fragment.jinja" - - class BillingInfoFormFragment( LoginRequiredMixin, FragmentMixin, SuccessMessageMixin, UpdateView ): diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index d6549184..f1ad16da 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-06-25 16:29+0200\n" +"POT-Creation-Date: 2025-08-23 15:30+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Maréchal \n" @@ -1708,27 +1708,27 @@ msgstr "500, Erreur Serveur" msgid "Welcome!" msgstr "Bienvenue !" -#: core/templates/core/base.jinja core/templates/core/base/navbar.jinja +#: core/templates/core/base/footer.jinja core/templates/core/base/navbar.jinja msgid "Contacts" msgstr "Contacts" -#: core/templates/core/base.jinja +#: core/templates/core/base/footer.jinja msgid "Legal notices" msgstr "Mentions légales" -#: core/templates/core/base.jinja +#: core/templates/core/base/footer.jinja msgid "Intellectual property" msgstr "Propriété intellectuelle" -#: core/templates/core/base.jinja +#: core/templates/core/base/footer.jinja msgid "Help & Documentation" msgstr "Aide & Documentation" -#: core/templates/core/base.jinja +#: core/templates/core/base/footer.jinja msgid "R&D" msgstr "R&D" -#: core/templates/core/base.jinja +#: core/templates/core/base/footer.jinja msgid "Site created by the IT Department of the AE" msgstr "Site réalisé par le Pôle Informatique de l'AE" @@ -3838,47 +3838,6 @@ msgstr "" msgid "this page" msgstr "cette page" -#: eboutic/templates/eboutic/eboutic_main.jinja -msgid "Eurockéennes 2025 partnership" -msgstr "Partenariat Eurockéennes 2025" - -#: eboutic/templates/eboutic/eboutic_main.jinja -msgid "" -"Our partner uses Weezevent to sell tickets. Weezevent may collect user info " -"according to its own privacy policy. By clicking the accept button you " -"consent to their terms of services." -msgstr "" -"Notre partenaire utilises Wezevent pour vendre ses billets. Weezevent peut " -"collecter des informations utilisateur conformément à sa propre politique de " -"confidentialité. En cliquant sur le bouton d'acceptation vous consentez à " -"leurs termes de service." - -#: eboutic/templates/eboutic/eboutic_main.jinja -msgid "Privacy policy" -msgstr "Politique de confidentialité" - -#: eboutic/templates/eboutic/eboutic_main.jinja -#: trombi/templates/trombi/comment_moderation.jinja -msgid "Accept" -msgstr "Accepter" - -#: eboutic/templates/eboutic/eboutic_main.jinja -msgid "" -"You must be subscribed to benefit from the partnership with the Eurockéennes." -msgstr "" -"Vous devez être cotisant pour bénéficier du partenariat avec les " -"Eurockéennes." - -#: eboutic/templates/eboutic/eboutic_main.jinja -#, python-format -msgid "" -"This partnership offers a discount of up to 33%% on tickets for Friday, " -"Saturday and Sunday, as well as the 3-day package from Friday to Sunday." -msgstr "" -"Ce partenariat permet de profiter d'une réduction jusqu'à 33%% sur les " -"billets du vendredi, du samedi et du dimanche, ainsi qu'au forfait 3 jours, " -"du vendredi au dimanche." - #: eboutic/templates/eboutic/eboutic_main.jinja msgid "There are no items available for sale" msgstr "Aucun article n'est disponible à la vente" @@ -5305,6 +5264,10 @@ msgstr "fin" msgid "Moderate Trombi comments" msgstr "Modérer les commentaires du Trombi" +#: trombi/templates/trombi/comment_moderation.jinja +msgid "Accept" +msgstr "Accepter" + #: trombi/templates/trombi/comment_moderation.jinja msgid "Reject" msgstr "Refuser" diff --git a/locale/fr/LC_MESSAGES/djangojs.po b/locale/fr/LC_MESSAGES/djangojs.po index bcb6d1de..0dc0a145 100644 --- a/locale/fr/LC_MESSAGES/djangojs.po +++ b/locale/fr/LC_MESSAGES/djangojs.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-05-18 12:17+0200\n" +"POT-Creation-Date: 2025-08-23 15:30+0200\n" "PO-Revision-Date: 2024-09-17 11:54+0200\n" "Last-Translator: Sli \n" "Language-Team: AE info \n" @@ -193,7 +193,7 @@ msgstr "Montrer moins" msgid "Show more" msgstr "Montrer plus" -#: core/static/bundled/user/family-graph-index.js +#: core/static/bundled/user/family-graph-index.ts msgid "family_tree.%(extension)s" msgstr "arbre_genealogique.%(extension)s" From 25099528bf13a79926cc285899d43de05503ba31 Mon Sep 17 00:00:00 2001 From: Sli Date: Sun, 24 Aug 2025 00:26:34 +0200 Subject: [PATCH 07/14] Improve eboutic readability --- eboutic/views.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/eboutic/views.py b/eboutic/views.py index f4762534..b52e8d83 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -133,28 +133,30 @@ class EbouticMainView(LoginRequiredMixin, FormView): context["products"] = self.products context["customer_amount"] = self.request.user.account_balance + purchases = ( + Customer.objects.filter(pk=self.customer.pk) + .annotate( + last_refill=Subquery( + Refilling.objects.filter( + counter__type="EBOUTIC", customer_id=self.customer.pk + ) + .order_by("-date") + .values("date")[:1] + ), + last_purchase=Subquery( + Selling.objects.filter( + counter__type="EBOUTIC", customer_id=self.customer.pk + ) + .order_by("-date") + .values("date")[:1] + ), + ) + .values_list("last_refill", "last_purchase") + )[0] + purchase_times = [ int(purchase.timestamp() * 1000) - for purchase in ( - Customer.objects.filter(pk=self.customer.pk) - .annotate( - last_refill=Subquery( - Refilling.objects.filter( - counter__type="EBOUTIC", customer_id=self.customer.pk - ) - .order_by("-date") - .values("date")[:1] - ), - last_purchase=Subquery( - Selling.objects.filter( - counter__type="EBOUTIC", customer_id=self.customer.pk - ) - .order_by("-date") - .values("date")[:1] - ), - ) - .values("last_refill", "last_purchase") - )[0].values() + for purchase in purchases if purchase is not None ] From ed9c718cf105da9c676d1e054b4d5b3f5352c8a3 Mon Sep 17 00:00:00 2001 From: Sli Date: Tue, 26 Aug 2025 10:30:08 +0200 Subject: [PATCH 08/14] Apply review comments --- eboutic/tests/test_basket.py | 62 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/eboutic/tests/test_basket.py b/eboutic/tests/test_basket.py index 8ea45dbd..ff7f2077 100644 --- a/eboutic/tests/test_basket.py +++ b/eboutic/tests/test_basket.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone import pytest from django.http import HttpResponse @@ -9,16 +9,13 @@ from django.utils.timezone import localdate from model_bakery import baker from pytest_django.asserts import assertRedirects -from club.models import Club from core.baker_recipes import subscriber_user from core.models import Group, User -from counter.baker_recipes import product_recipe +from counter.baker_recipes import product_recipe, refill_recipe, sale_recipe from counter.models import ( Counter, Customer, ProductType, - Refilling, - Selling, get_eboutic, ) from counter.tests.test_counter import BasketItem @@ -45,12 +42,12 @@ def test_eboutic_access_unregistered(client: Client): @pytest.mark.django_db def test_eboutic_access_new_customer(client: Client): user = baker.make(User) - assert Customer.objects.filter(user=user).first() is None + assert not Customer.objects.filter(user=user).exists() client.force_login(user) assert client.get(reverse("eboutic:main")).status_code == 200 - assert Customer.objects.filter(user=user).first() + assert Customer.objects.filter(user=user).exists() @pytest.mark.django_db @@ -69,22 +66,33 @@ def test_eboutic_access_old_customer(client: Client): ("sellings", "refillings", "expected"), ( ([], [], None), - ([datetime(2025, 3, 7, 1, 2, 3)], [], datetime(2025, 3, 7, 1, 2, 3)), - ([], [datetime(2025, 3, 7, 1, 2, 3)], datetime(2025, 3, 7, 1, 2, 3)), ( - [datetime(2025, 2, 7, 1, 2, 3)], - [datetime(2025, 3, 7, 1, 2, 3)], - datetime(2025, 3, 7, 1, 2, 3), + [datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc)], + [], + datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc), ), ( - [datetime(2025, 3, 7, 1, 2, 3)], - [datetime(2025, 2, 7, 1, 2, 3)], - datetime(2025, 3, 7, 1, 2, 3), + [], + [datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc)], + datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc), ), ( - [datetime(2025, 3, 7, 1, 2, 3), datetime(2025, 2, 7, 1, 2, 3)], - [datetime(2025, 3, 7, 1, 2, 3)], - datetime(2025, 3, 7, 1, 2, 3), + [datetime(2025, 2, 7, 1, 2, 3, tzinfo=timezone.utc)], + [datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc)], + datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc), + ), + ( + [datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc)], + [datetime(2025, 2, 7, 1, 2, 3, tzinfo=timezone.utc)], + datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc), + ), + ( + [ + datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc), + datetime(2025, 2, 7, 1, 2, 3, tzinfo=timezone.utc), + ], + [datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc)], + datetime(2025, 3, 7, 1, 2, 3, tzinfo=timezone.utc), ), ), ) @@ -96,24 +104,16 @@ def test_eboutic_basket_expiry( ): eboutic = get_eboutic() - user = baker.make(User) - customer = Customer.get_or_create(user)[0] + customer = baker.make(Customer) - client.force_login(user) + client.force_login(customer.user) for date in sellings: - baker.make( - Selling, - customer=customer, - counter=eboutic, - club=baker.make(Club), - seller=user, - date=date, - is_validated=True, # Ignore not enough money warnings + sale_recipe.make( + customer=customer, counter=eboutic, date=date, is_validated=True ) - for date in refillings: - baker.make(Refilling, customer=customer, counter=eboutic, date=date) + refill_recipe.make(customer=customer, counter=eboutic, date=date) assert ( f'x-data="basket({int(expected.timestamp() * 1000) if expected else "null"})"' From e864e825737714a7bc5937cdbea1cf3072707fee Mon Sep 17 00:00:00 2001 From: imperosol Date: Thu, 28 Aug 2025 16:31:54 +0200 Subject: [PATCH 09/14] replace deprecated CheckConstraint.check by CheckConstraint.condition --- ..._alter_club_board_group_alter_club_members_group_and_more.py | 2 +- club/models.py | 2 +- .../0008_alter_news_options_alter_newsdate_options_and_more.py | 2 +- com/models.py | 2 +- ...ngroup_alter_group_description_alter_user_groups_and_more.py | 2 +- core/models.py | 2 +- .../0030_returnableproduct_returnableproductbalance_and_more.py | 2 +- counter/models.py | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/club/migrations/0013_alter_club_board_group_alter_club_members_group_and_more.py b/club/migrations/0013_alter_club_board_group_alter_club_members_group_and_more.py index 21480bda..ca736864 100644 --- a/club/migrations/0013_alter_club_board_group_alter_club_members_group_and_more.py +++ b/club/migrations/0013_alter_club_board_group_alter_club_members_group_and_more.py @@ -29,7 +29,7 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="membership", constraint=models.CheckConstraint( - check=models.Q(("end_date__gte", models.F("start_date"))), + condition=models.Q(("end_date__gte", models.F("start_date"))), name="end_after_start", ), ), diff --git a/club/models.py b/club/models.py index e7e99cda..fc5aa64b 100644 --- a/club/models.py +++ b/club/models.py @@ -347,7 +347,7 @@ class Membership(models.Model): class Meta: constraints = [ models.CheckConstraint( - check=Q(end_date__gte=F("start_date")), name="end_after_start" + condition=Q(end_date__gte=F("start_date")), name="end_after_start" ), ] diff --git a/com/migrations/0008_alter_news_options_alter_newsdate_options_and_more.py b/com/migrations/0008_alter_news_options_alter_newsdate_options_and_more.py index 98b09b65..f15cd5cb 100644 --- a/com/migrations/0008_alter_news_options_alter_newsdate_options_and_more.py +++ b/com/migrations/0008_alter_news_options_alter_newsdate_options_and_more.py @@ -54,7 +54,7 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="newsdate", constraint=models.CheckConstraint( - check=models.Q(("end_date__gte", models.F("start_date"))), + condition=models.Q(("end_date__gte", models.F("start_date"))), name="news_date_end_date_after_start_date", ), ), diff --git a/com/models.py b/com/models.py index 8c7111e8..ebc458e7 100644 --- a/com/models.py +++ b/com/models.py @@ -212,7 +212,7 @@ class NewsDate(models.Model): verbose_name_plural = _("news dates") constraints = [ models.CheckConstraint( - check=Q(end_date__gte=F("start_date")), + condition=Q(end_date__gte=F("start_date")), name="news_date_end_date_after_start_date", ) ] diff --git a/core/migrations/0043_bangroup_alter_group_description_alter_user_groups_and_more.py b/core/migrations/0043_bangroup_alter_group_description_alter_user_groups_and_more.py index daba4097..81cb2332 100644 --- a/core/migrations/0043_bangroup_alter_group_description_alter_user_groups_and_more.py +++ b/core/migrations/0043_bangroup_alter_group_description_alter_user_groups_and_more.py @@ -154,7 +154,7 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="userban", constraint=models.CheckConstraint( - check=models.Q(("expires_at__gte", models.F("created_at"))), + condition=models.Q(("expires_at__gte", models.F("created_at"))), name="user_ban_end_after_start", ), ), diff --git a/core/models.py b/core/models.py index 0c65e043..64b4b778 100644 --- a/core/models.py +++ b/core/models.py @@ -745,7 +745,7 @@ class UserBan(models.Model): fields=["ban_group", "user"], name="unique_ban_type_per_user" ), models.CheckConstraint( - check=Q(expires_at__gte=F("created_at")), + condition=Q(expires_at__gte=F("created_at")), name="user_ban_end_after_start", ), ] diff --git a/counter/migrations/0030_returnableproduct_returnableproductbalance_and_more.py b/counter/migrations/0030_returnableproduct_returnableproductbalance_and_more.py index 82378636..a7565b62 100644 --- a/counter/migrations/0030_returnableproduct_returnableproductbalance_and_more.py +++ b/counter/migrations/0030_returnableproduct_returnableproductbalance_and_more.py @@ -58,7 +58,7 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="returnableproduct", constraint=models.CheckConstraint( - check=models.Q( + condition=models.Q( ("product", models.F("returned_product")), _negated=True ), name="returnableproduct_product_different_from_returned", diff --git a/counter/models.py b/counter/models.py index 0f46176b..d2b9a927 100644 --- a/counter/models.py +++ b/counter/models.py @@ -1278,7 +1278,7 @@ class ReturnableProduct(models.Model): verbose_name_plural = _("returnable products") constraints = [ models.CheckConstraint( - check=~Q(product=F("returned_product")), + condition=~Q(product=F("returned_product")), name="returnableproduct_product_different_from_returned", violation_error_message=_( "The returnable product cannot be the same as the returned one" From 142dd6a16f174281d7cfc0502f2f6cefd693ebc8 Mon Sep 17 00:00:00 2001 From: Sli Date: Thu, 28 Aug 2025 22:06:35 +0200 Subject: [PATCH 10/14] Update dependabot config --- .github/dependabot.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6dfe4585..d9af29db 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,11 +4,19 @@ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 -updates: - - package-ecosystem: "pip" # See documentation for possible values - directory: "/" # Location of package manifests + +multi-ecosystem-groups: + common: + directory: "/" schedule: interval: "weekly" target-branch: "taiste" commit-message: - prefix: "[UPDATE] " \ No newline at end of file + prefix: "[UPDATE] " + +updates: + - package-ecosystem: "uv" + multi-ecosystem-group: "common" + + - package-ecosystem: "npm" + multi-ecosystem-group: "common" From f3fe67cf7582bf483e075ffc12665c1fe2329466 Mon Sep 17 00:00:00 2001 From: Sli Date: Thu, 28 Aug 2025 23:36:18 +0200 Subject: [PATCH 11/14] Update dependencies --- package-lock.json | 1070 +++++++++++++++++++++++---------------------- package.json | 4 +- pyproject.toml | 8 +- uv.lock | 122 +++--- 4 files changed, 617 insertions(+), 587 deletions(-) diff --git a/package-lock.json b/package-lock.json index 44e71934..4d92469f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,9 +50,9 @@ "@types/jquery": "^3.5.31", "@types/js-cookie": "^3.0.6", "typescript": "^5.8.3", - "vite": "^6.2.5", + "vite": "^6.2.6", "vite-bundle-visualizer": "^1.2.1", - "vite-plugin-static-copy": "^3.0.2" + "vite-plugin-static-copy": "^3.1.2" } }, "node_modules/@alpinejs/sort": { @@ -97,9 +97,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", - "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "dev": true, "license": "MIT", "engines": { @@ -107,22 +107,22 @@ } }, "node_modules/@babel/core": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", - "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", + "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.4", - "@babel/parser": "^7.27.4", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.27.4", - "@babel/types": "^7.27.3", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -138,16 +138,16 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", - "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.5", - "@babel/types": "^7.27.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -185,18 +185,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", - "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.27.1", + "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "engines": { @@ -225,22 +225,32 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", - "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", @@ -270,15 +280,15 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -391,42 +401,42 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", - "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", + "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", - "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.28.2" }, "bin": { "parser": "bin/babel-parser.js" @@ -503,14 +513,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", - "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -598,15 +608,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", - "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -650,9 +660,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.5.tgz", - "integrity": "sha512-JF6uE2s67f0y2RZcm2kpAUEbD50vH62TyWVebxwHAlbSdM49VqPz8t4a1uIjp4NIOIZ4xzLfjY5emt/RCyC7TQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", + "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", "dev": true, "license": "MIT", "dependencies": { @@ -683,13 +693,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", - "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { @@ -700,18 +710,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", - "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", + "integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.27.1", - "globals": "^11.1.0" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -738,13 +748,14 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.3.tgz", - "integrity": "sha512-s4Jrok82JpiaIprtY2nHsYmrThKvvwgHwjgd7UMiYhZaN0asdXNLr0y+NjTfkA7SyQE5i2Fb7eawUOZmLvyqOA==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -819,6 +830,23 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", @@ -1086,16 +1114,17 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.3.tgz", - "integrity": "sha512-7ZZtznF9g4l2JCImCo5LNKFHB5eXnN39lLtLY5Tg+VkR0jwOt7TBciMckuiQIOIW7L5tkQOCh3bVGYeXgMx52Q==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", + "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.27.3", - "@babel/plugin-transform-parameters": "^7.27.1" + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -1155,9 +1184,9 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", - "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "dev": true, "license": "MIT", "dependencies": { @@ -1222,9 +1251,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.5.tgz", - "integrity": "sha512-uhB8yHerfe3MWnuLAhEbeQ4afVoqv8BQsPqrTv7e/jZ9y00kJL6l9a/f4OWaKxotmjzewfEyXE1vgDJenkQ2/Q==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", + "integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", "dev": true, "license": "MIT", "dependencies": { @@ -1419,13 +1448,13 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", - "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", + "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", @@ -1433,25 +1462,26 @@ "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.0", "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.3", "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.27.1", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", @@ -1468,15 +1498,15 @@ "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.27.2", + "@babel/plugin-transform-object-rest-spread": "^7.28.0", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1", - "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.3", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -1489,10 +1519,10 @@ "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.11.0", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.40.0", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "engines": { @@ -1518,9 +1548,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", + "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1542,28 +1572,28 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", - "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", - "@babel/parser": "^7.27.4", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", - "@babel/types": "^7.27.3", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/types": "^7.28.2", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", - "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1739,9 +1769,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", - "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ "ppc64" ], @@ -1756,9 +1786,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", - "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", "cpu": [ "arm" ], @@ -1773,9 +1803,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", - "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", "cpu": [ "arm64" ], @@ -1790,9 +1820,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", - "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", "cpu": [ "x64" ], @@ -1807,9 +1837,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", - "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -1824,9 +1854,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", - "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], @@ -1841,9 +1871,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", - "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], @@ -1858,9 +1888,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", - "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], @@ -1875,9 +1905,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", - "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], @@ -1892,9 +1922,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", - "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], @@ -1909,9 +1939,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", - "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ "ia32" ], @@ -1926,9 +1956,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", - "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ "loong64" ], @@ -1943,9 +1973,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", - "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ "mips64el" ], @@ -1960,9 +1990,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", - "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ "ppc64" ], @@ -1977,9 +2007,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", - "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ "riscv64" ], @@ -1994,9 +2024,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", - "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ "s390x" ], @@ -2011,9 +2041,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", - "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -2028,9 +2058,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", - "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], @@ -2045,9 +2075,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", - "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ "x64" ], @@ -2062,9 +2092,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", - "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ "arm64" ], @@ -2079,9 +2109,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", - "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ "x64" ], @@ -2095,10 +2125,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", - "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ "x64" ], @@ -2113,9 +2160,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", - "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], @@ -2130,9 +2177,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", - "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], @@ -2147,9 +2194,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", - "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], @@ -2164,28 +2211,28 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.1.tgz", - "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.9" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.1.tgz", - "integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.1", - "@floating-ui/utils": "^0.2.9" + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", - "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, "node_modules/@fortawesome/fontawesome-free": { @@ -2198,40 +2245,40 @@ } }, "node_modules/@fullcalendar/core": { - "version": "6.1.17", - "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.17.tgz", - "integrity": "sha512-0W7lnIrv18ruJ5zeWBeNZXO8qCWlzxDdp9COFEsZnyNjiEhUVnrW/dPbjRKYpL0edGG0/Lhs0ghp1z/5ekt8ZA==", + "version": "6.1.19", + "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.19.tgz", + "integrity": "sha512-z0aVlO5e4Wah6p6mouM0UEqtRf1MZZPt4mwzEyU6kusaNL+dlWQgAasF2cK23hwT4cmxkEmr4inULXgpyeExdQ==", "license": "MIT", "dependencies": { "preact": "~10.12.1" } }, "node_modules/@fullcalendar/daygrid": { - "version": "6.1.17", - "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.17.tgz", - "integrity": "sha512-K7m+pd7oVJ9fW4h7CLDdDGJbc9szJ1xDU1DZ2ag+7oOo1aCNLv44CehzkkknM6r8EYlOOhgaelxQpKAI4glj7A==", + "version": "6.1.19", + "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.19.tgz", + "integrity": "sha512-IAAfnMICnVWPjpT4zi87i3FEw0xxSza0avqY/HedKEz+l5MTBYvCDPOWDATpzXoLut3aACsjktIyw9thvIcRYQ==", "license": "MIT", "peerDependencies": { - "@fullcalendar/core": "~6.1.17" + "@fullcalendar/core": "~6.1.19" } }, "node_modules/@fullcalendar/icalendar": { - "version": "6.1.17", - "resolved": "https://registry.npmjs.org/@fullcalendar/icalendar/-/icalendar-6.1.17.tgz", - "integrity": "sha512-Gv47quN1/les/i5Gjdqo2q1arbTQjFFsK6UUBX/LLLoYiduzfX9eaX/RUpFF51BCl0EF1+eDXH7Figc1FSWpSA==", + "version": "6.1.19", + "resolved": "https://registry.npmjs.org/@fullcalendar/icalendar/-/icalendar-6.1.19.tgz", + "integrity": "sha512-uaJnTP99cM2ZiFmYaSLfayX9TmF0DklIf2SpgwMDCMEqtNYm+TbCotDUrfMDWVFYPr4uCHk0TjlM5mS3U3wB9g==", "license": "MIT", "peerDependencies": { - "@fullcalendar/core": "~6.1.17", + "@fullcalendar/core": "~6.1.19", "ical.js": "^1.4.0" } }, "node_modules/@fullcalendar/list": { - "version": "6.1.17", - "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.17.tgz", - "integrity": "sha512-fkyK49F9IxwlGUBVhJGsFpd/LTi/vRVERLIAe1HmBaGkjwpxnynm8TMLb9mZip97wvDk3CmZWduMe6PxscAlow==", + "version": "6.1.19", + "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-6.1.19.tgz", + "integrity": "sha512-knZHpAVF0LbzZpSJSUmLUUzF0XlU/MRGK+Py2s0/mP93bCtno1k2L3XPs/kzh528hSjehwLm89RgKTSfW1P6cA==", "license": "MIT", "peerDependencies": { - "@fullcalendar/core": "~6.1.17" + "@fullcalendar/core": "~6.1.19" } }, "node_modules/@hey-api/json-schema-ref-parser": { @@ -2320,18 +2367,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -2344,27 +2387,17 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2424,9 +2457,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -2447,9 +2480,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz", - "integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.49.0.tgz", + "integrity": "sha512-rlKIeL854Ed0e09QGYFlmDNbka6I3EQFw7iZuugQjMb11KMpJCLPFL4ZPbMfaEhLADEL1yx0oujGkBQ7+qW3eA==", "cpu": [ "arm" ], @@ -2461,9 +2494,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz", - "integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.49.0.tgz", + "integrity": "sha512-cqPpZdKUSQYRtLLr6R4X3sD4jCBO1zUmeo3qrWBCqYIeH8Q3KRL4F3V7XJ2Rm8/RJOQBZuqzQGWPjjvFUcYa/w==", "cpu": [ "arm64" ], @@ -2475,9 +2508,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz", - "integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz", + "integrity": "sha512-99kMMSMQT7got6iYX3yyIiJfFndpojBmkHfTc1rIje8VbjhmqBXE+nb7ZZP3A5skLyujvT0eIUCUsxAe6NjWbw==", "cpu": [ "arm64" ], @@ -2489,9 +2522,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz", - "integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.49.0.tgz", + "integrity": "sha512-y8cXoD3wdWUDpjOLMKLx6l+NFz3NlkWKcBCBfttUn+VGSfgsQ5o/yDUGtzE9HvsodkP0+16N0P4Ty1VuhtRUGg==", "cpu": [ "x64" ], @@ -2503,9 +2536,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz", - "integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.49.0.tgz", + "integrity": "sha512-3mY5Pr7qv4GS4ZvWoSP8zha8YoiqrU+e0ViPvB549jvliBbdNLrg2ywPGkgLC3cmvN8ya3za+Q2xVyT6z+vZqA==", "cpu": [ "arm64" ], @@ -2517,9 +2550,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz", - "integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.49.0.tgz", + "integrity": "sha512-C9KzzOAQU5gU4kG8DTk+tjdKjpWhVWd5uVkinCwwFub2m7cDYLOdtXoMrExfeBmeRy9kBQMkiyJ+HULyF1yj9w==", "cpu": [ "x64" ], @@ -2531,9 +2564,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz", - "integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.49.0.tgz", + "integrity": "sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w==", "cpu": [ "arm" ], @@ -2545,9 +2578,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz", - "integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.49.0.tgz", + "integrity": "sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA==", "cpu": [ "arm" ], @@ -2559,9 +2592,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz", - "integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.49.0.tgz", + "integrity": "sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg==", "cpu": [ "arm64" ], @@ -2573,9 +2606,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz", - "integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.49.0.tgz", + "integrity": "sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg==", "cpu": [ "arm64" ], @@ -2587,9 +2620,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz", - "integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.49.0.tgz", + "integrity": "sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ==", "cpu": [ "loong64" ], @@ -2600,10 +2633,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz", - "integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.49.0.tgz", + "integrity": "sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g==", "cpu": [ "ppc64" ], @@ -2615,9 +2648,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz", - "integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.49.0.tgz", + "integrity": "sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw==", "cpu": [ "riscv64" ], @@ -2629,9 +2662,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz", - "integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.49.0.tgz", + "integrity": "sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw==", "cpu": [ "riscv64" ], @@ -2643,9 +2676,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz", - "integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.49.0.tgz", + "integrity": "sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A==", "cpu": [ "s390x" ], @@ -2657,9 +2690,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz", - "integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.49.0.tgz", + "integrity": "sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA==", "cpu": [ "x64" ], @@ -2671,9 +2704,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz", - "integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.49.0.tgz", + "integrity": "sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg==", "cpu": [ "x64" ], @@ -2685,9 +2718,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz", - "integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.49.0.tgz", + "integrity": "sha512-wkNRzfiIGaElC9kXUT+HLx17z7D0jl+9tGYRKwd8r7cUqTL7GYAvgUY++U2hK6Ar7z5Z6IRRoWC8kQxpmM7TDA==", "cpu": [ "arm64" ], @@ -2699,9 +2732,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz", - "integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.49.0.tgz", + "integrity": "sha512-gq5aW/SyNpjp71AAzroH37DtINDcX1Qw2iv9Chyz49ZgdOP3NV8QCyKZUrGsYX9Yyggj5soFiRCgsL3HwD8TdA==", "cpu": [ "ia32" ], @@ -2713,9 +2746,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz", - "integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz", + "integrity": "sha512-gEtqFbzmZLFk2xKh7g0Rlo8xzho8KrEFEkzvHbfUGkrgXOpZ4XagQ6n+wIZFNh1nTb8UD16J4nFSFKXYgnbdBg==", "cpu": [ "x64" ], @@ -2727,75 +2760,75 @@ ] }, "node_modules/@sentry-internal/browser-utils": { - "version": "9.29.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.29.0.tgz", - "integrity": "sha512-Wp6UJCDVV2KVK+TG8GwdLZyDy4GtUYDmVhGMpHKPS3G/Qgpf36cY/XHwChwaHZ5P9Bk1sjS9Ok698J59S8L2nw==", + "version": "9.46.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.46.0.tgz", + "integrity": "sha512-Q0CeHym9wysku8mYkORXmhtlBE0IrafAI+NiPSqxOBKXGOCWKVCvowHuAF56GwPFic2rSrRnub5fWYv7T1jfEQ==", "license": "MIT", "dependencies": { - "@sentry/core": "9.29.0" + "@sentry/core": "9.46.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry-internal/feedback": { - "version": "9.29.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.29.0.tgz", - "integrity": "sha512-ADvetGrtr+RfYcQKrQxah4fHs/xDJ/VjbStVMSuaNllzwWPYNkWIGFE6YjQ7wZszj0DQIu5/H+B6lZKsFYk4xw==", + "version": "9.46.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.46.0.tgz", + "integrity": "sha512-KLRy3OolDkGdPItQ3obtBU2RqDt9+KE8z7r7Gsu7c6A6A89m8ZVlrxee3hPQt6qp0YY0P8WazpedU3DYTtaT8w==", "license": "MIT", "dependencies": { - "@sentry/core": "9.29.0" + "@sentry/core": "9.46.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry-internal/replay": { - "version": "9.29.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.29.0.tgz", - "integrity": "sha512-we/1JPRje8sNowQCyogOV1OYWuDOP/3XmDi48XoFG2HB0XMl2HfL5LI8AvgAvC/5nrqVAAo4ktbjoVLm1fb7rg==", + "version": "9.46.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.46.0.tgz", + "integrity": "sha512-+8JUblxSSnN0FXcmOewbN+wIc1dt6/zaSeAvt2xshrfrLooVullcGsuLAiPhY0d/e++Fk06q1SAl9g4V0V13gg==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "9.29.0", - "@sentry/core": "9.29.0" + "@sentry-internal/browser-utils": "9.46.0", + "@sentry/core": "9.46.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "9.29.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.29.0.tgz", - "integrity": "sha512-TrQYhSAVPhyenvu0fNkon7BznFibu1mzS5bCudxhgOWajZluUVrXcbp8Q3WZ3R+AogrcgA3Vy6aumP/+fMKdwg==", + "version": "9.46.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.46.0.tgz", + "integrity": "sha512-QcBjrdRWFJrrrjbmrr2bbrp2R9RYj1KMEbhHNT2Lm1XplIQw+tULEKOHxNtkUFSLR1RNje7JQbxhzM1j95FxVQ==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "9.29.0", - "@sentry/core": "9.29.0" + "@sentry-internal/replay": "9.46.0", + "@sentry/core": "9.46.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry/browser": { - "version": "9.29.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.29.0.tgz", - "integrity": "sha512-+GFX/yb+rh6V1fSgTYM6ttAgledl2aUR3T3Rg86HNuegbdX8ym6lOtUOIZ0j9jPK015HR47KIPyIZVZZJ7Rj9g==", + "version": "9.46.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.46.0.tgz", + "integrity": "sha512-NOnCTQCM0NFuwbyt4DYWDNO2zOTj1mCf43hJqGDFb1XM9F++7zAmSNnCx4UrEoBTiFOy40McJwBBk9D1blSktA==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "9.29.0", - "@sentry-internal/feedback": "9.29.0", - "@sentry-internal/replay": "9.29.0", - "@sentry-internal/replay-canvas": "9.29.0", - "@sentry/core": "9.29.0" + "@sentry-internal/browser-utils": "9.46.0", + "@sentry-internal/feedback": "9.46.0", + "@sentry-internal/replay": "9.46.0", + "@sentry-internal/replay-canvas": "9.46.0", + "@sentry/core": "9.46.0" }, "engines": { "node": ">=18" } }, "node_modules/@sentry/core": { - "version": "9.29.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.29.0.tgz", - "integrity": "sha512-wDyNe45PM+RCGtUn1tK7LzJ08ksv8i8KRUHrst7lsinEfRm83YH+wbWrPmwkVNEngUZvYkHwGLbNXM7xgFUuDQ==", + "version": "9.46.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.46.0.tgz", + "integrity": "sha512-it7JMFqxVproAgEtbLgCVBYtQ9fIb+Bu0JD+cEplTN/Ukpe6GaolyYib5geZqslVxhp2sQgT+58aGvfd/k0N8Q==", "license": "MIT", "engines": { "node": ">=18" @@ -2857,9 +2890,9 @@ "license": "MIT" }, "node_modules/@types/jquery": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.32.tgz", - "integrity": "sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.33.tgz", + "integrity": "sha512-SeyVJXlCZpEki5F0ghuYe+L+PprQta6nRZqhONt9F13dWBtR/ftoaIbdRQ7cis7womE+X2LKhsDdDtkkDhJS6g==", "dev": true, "license": "MIT", "dependencies": { @@ -2887,9 +2920,9 @@ "license": "MIT" }, "node_modules/@types/sizzle": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz", - "integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==", + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", "dev": true, "license": "MIT" }, @@ -2924,9 +2957,9 @@ "license": "MIT" }, "node_modules/@zip.js/zip.js": { - "version": "2.7.62", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.62.tgz", - "integrity": "sha512-OaLvZ8j4gCkLn048ypkZu29KX30r8/OfFF2w4Jo5WXFr+J04J+lzJ5TKZBVgFXhlvSkqNFQdfnY1Q8TMTCyBVA==", + "version": "2.7.72", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.72.tgz", + "integrity": "sha512-3/A4JwrgkvGBlCxtItjxs8HrNbuTAAl/zlGkV6tC5Fb5k5nk4x2Dqxwl/YnUys5Ch+QB01eJ8Q5K/J2uXfy9Vw==", "license": "BSD-3-Clause", "engines": { "bun": ">=0.7.0", @@ -2935,9 +2968,9 @@ } }, "node_modules/3d-force-graph": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/3d-force-graph/-/3d-force-graph-1.77.0.tgz", - "integrity": "sha512-w2MlrCeMJxXwhz5gtRZ7mLU4xW5DD2U6VSEfFv8pvnvSNPYPuAIKjbJoZekfv7yFmMaWnNy/2RfRcgC5oGr2KQ==", + "version": "1.78.4", + "resolved": "https://registry.npmjs.org/3d-force-graph/-/3d-force-graph-1.78.4.tgz", + "integrity": "sha512-R722H4PRttwt3dddnV8+XRCQ9xQzWhI3j+8aXZ/Hlv4Yr6hR95/DjO/pMXpvQSQ1XDTV2dUl7sX2rajSm4k8SQ==", "license": "MIT", "dependencies": { "accessor-fn": "1", @@ -2992,9 +3025,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz", + "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==", "license": "MIT", "engines": { "node": ">=12" @@ -3050,14 +3083,14 @@ "license": "Python-2.0" }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", - "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.4", + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { @@ -3065,27 +3098,27 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", - "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3", - "core-js-compat": "^3.40.0" + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", - "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.4" + "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3118,9 +3151,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", - "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz", + "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==", "dev": true, "funding": [ { @@ -3138,8 +3171,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001718", - "electron-to-chromium": "^1.5.160", + "caniuse-lite": "^1.0.30001737", + "electron-to-chromium": "^1.5.211", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -3206,9 +3239,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001723", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz", - "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==", + "version": "1.0.30001737", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz", + "integrity": "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==", "dev": true, "funding": [ { @@ -3369,9 +3402,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.19", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.19.tgz", - "integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==", + "version": "5.65.20", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.20.tgz", + "integrity": "sha512-i5dLDDxwkFCbhjvL2pNjShsojoL3XHyDwsGv1jqETUoW+lzpBKKqNTUWgQwVAOa0tUm4BwekT455ujafi8payA==", "license": "MIT" }, "node_modules/codemirror-spell-checker": { @@ -3446,13 +3479,13 @@ "license": "MIT" }, "node_modules/core-js-compat": { - "version": "3.43.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz", - "integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==", + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", + "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.0" + "browserslist": "^4.25.3" }, "funding": { "type": "opencollective", @@ -3480,9 +3513,9 @@ } }, "node_modules/cytoscape": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.32.0.tgz", - "integrity": "sha512-5JHBC9n75kz5851jeklCPmZWcg3hUe6sjqJvyk3+hVqFaKcHwHgxsjeN1yLmggoUc6STbtm9/NQyabQehfjvWQ==", + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", + "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", "engines": { "node": ">=0.10" @@ -3756,9 +3789,9 @@ "license": "MIT" }, "node_modules/dotenv": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -3788,9 +3821,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.167", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.167.tgz", - "integrity": "sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==", + "version": "1.5.211", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz", + "integrity": "sha512-IGBvimJkotaLzFnwIVgW9/UD/AOJ2tByUmeOrtqBfACSbAw5b1G0XpvdaieKyc7ULmbwXVx+4e4Be8pOPBrYkw==", "dev": true, "license": "ISC" }, @@ -3801,9 +3834,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", - "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3814,31 +3847,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.5", - "@esbuild/android-arm": "0.25.5", - "@esbuild/android-arm64": "0.25.5", - "@esbuild/android-x64": "0.25.5", - "@esbuild/darwin-arm64": "0.25.5", - "@esbuild/darwin-x64": "0.25.5", - "@esbuild/freebsd-arm64": "0.25.5", - "@esbuild/freebsd-x64": "0.25.5", - "@esbuild/linux-arm": "0.25.5", - "@esbuild/linux-arm64": "0.25.5", - "@esbuild/linux-ia32": "0.25.5", - "@esbuild/linux-loong64": "0.25.5", - "@esbuild/linux-mips64el": "0.25.5", - "@esbuild/linux-ppc64": "0.25.5", - "@esbuild/linux-riscv64": "0.25.5", - "@esbuild/linux-s390x": "0.25.5", - "@esbuild/linux-x64": "0.25.5", - "@esbuild/netbsd-arm64": "0.25.5", - "@esbuild/netbsd-x64": "0.25.5", - "@esbuild/openbsd-arm64": "0.25.5", - "@esbuild/openbsd-x64": "0.25.5", - "@esbuild/sunos-x64": "0.25.5", - "@esbuild/win32-arm64": "0.25.5", - "@esbuild/win32-ia32": "0.25.5", - "@esbuild/win32-x64": "0.25.5" + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, "node_modules/escalade": { @@ -3869,11 +3903,14 @@ } }, "node_modules/fdir": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", - "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -3951,9 +3988,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", "dev": true, "license": "MIT", "dependencies": { @@ -4105,16 +4142,6 @@ "node": ">= 6" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -4158,9 +4185,9 @@ } }, "node_modules/htmx.org": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.4.tgz", - "integrity": "sha512-HLxMCdfXDOJirs3vBZl/ZLoY+c7PfM4Ahr2Ad4YXh6d22T5ltbTXFFkpx9Tgb2vvmWFMbIc3LqN2ToNkZJvyYQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.6.tgz", + "integrity": "sha512-7ythjYneGSk3yCHgtCnQeaoF+D+o7U2LF37WU3O0JYv3gTZSicdEFiI/Ai/NJyC5ZpYJWMpUb11OC5Lr6AfAqA==", "license": "0BSD" }, "node_modules/ical.js": { @@ -4348,9 +4375,9 @@ } }, "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "dev": true, "license": "MIT", "bin": { @@ -4419,9 +4446,9 @@ } }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", "dependencies": { @@ -4450,9 +4477,9 @@ "license": "EPL-1.0" }, "node_modules/lit-html": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.0.tgz", - "integrity": "sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.1.tgz", + "integrity": "sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==", "license": "BSD-3-Clause", "dependencies": { "@types/trusted-types": "^2.0.2" @@ -4489,13 +4516,13 @@ } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.18", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/marked": { @@ -4592,16 +4619,16 @@ } }, "node_modules/mlly": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", - "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", "dev": true, "license": "MIT", "dependencies": { - "acorn": "^8.14.0", - "pathe": "^2.0.1", - "pkg-types": "^1.3.0", - "ufo": "^1.5.4" + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" } }, "node_modules/mlly/node_modules/pathe": { @@ -4726,9 +4753,9 @@ } }, "node_modules/node-fetch-native": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", - "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", "dev": true, "license": "MIT" }, @@ -4885,9 +4912,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -4929,9 +4956,9 @@ } }, "node_modules/postcss": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz", - "integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -5095,13 +5122,13 @@ } }, "node_modules/rollup": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz", - "integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz", + "integrity": "sha512-3IVq0cGJ6H7fKXXEdVt+RcYvRCt8beYY9K1760wGQwSAHZcS9eot1zDG5axUbcp/kWRi5zKIIDX8MoKv/TzvZA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -5111,26 +5138,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.43.0", - "@rollup/rollup-android-arm64": "4.43.0", - "@rollup/rollup-darwin-arm64": "4.43.0", - "@rollup/rollup-darwin-x64": "4.43.0", - "@rollup/rollup-freebsd-arm64": "4.43.0", - "@rollup/rollup-freebsd-x64": "4.43.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", - "@rollup/rollup-linux-arm-musleabihf": "4.43.0", - "@rollup/rollup-linux-arm64-gnu": "4.43.0", - "@rollup/rollup-linux-arm64-musl": "4.43.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-musl": "4.43.0", - "@rollup/rollup-linux-s390x-gnu": "4.43.0", - "@rollup/rollup-linux-x64-gnu": "4.43.0", - "@rollup/rollup-linux-x64-musl": "4.43.0", - "@rollup/rollup-win32-arm64-msvc": "4.43.0", - "@rollup/rollup-win32-ia32-msvc": "4.43.0", - "@rollup/rollup-win32-x64-msvc": "4.43.0", + "@rollup/rollup-android-arm-eabi": "4.49.0", + "@rollup/rollup-android-arm64": "4.49.0", + "@rollup/rollup-darwin-arm64": "4.49.0", + "@rollup/rollup-darwin-x64": "4.49.0", + "@rollup/rollup-freebsd-arm64": "4.49.0", + "@rollup/rollup-freebsd-x64": "4.49.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.49.0", + "@rollup/rollup-linux-arm-musleabihf": "4.49.0", + "@rollup/rollup-linux-arm64-gnu": "4.49.0", + "@rollup/rollup-linux-arm64-musl": "4.49.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.49.0", + "@rollup/rollup-linux-ppc64-gnu": "4.49.0", + "@rollup/rollup-linux-riscv64-gnu": "4.49.0", + "@rollup/rollup-linux-riscv64-musl": "4.49.0", + "@rollup/rollup-linux-s390x-gnu": "4.49.0", + "@rollup/rollup-linux-x64-gnu": "4.49.0", + "@rollup/rollup-linux-x64-musl": "4.49.0", + "@rollup/rollup-win32-arm64-msvc": "4.49.0", + "@rollup/rollup-win32-ia32-msvc": "4.49.0", + "@rollup/rollup-win32-x64-msvc": "4.49.0", "fsevents": "~2.3.2" } }, @@ -5223,22 +5250,15 @@ } }, "node_modules/rollup-plugin-visualizer/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": ">= 8" + "node": ">= 12" } }, - "node_modules/rollup/node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -5466,9 +5486,9 @@ "license": "MIT" }, "node_modules/three-forcegraph": { - "version": "1.42.13", - "resolved": "https://registry.npmjs.org/three-forcegraph/-/three-forcegraph-1.42.13.tgz", - "integrity": "sha512-BoG5fB3nlAFeIyiLuFquvWIjt8DA2gdPWlqW/8V8xQcEO7otMmeN2/WWHCP7cWzKEImULxpJ6bNLmmt7TTJaiw==", + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/three-forcegraph/-/three-forcegraph-1.43.0.tgz", + "integrity": "sha512-1AqLmTCjjjwcuccObG96fCxiRnNJjCLdA5Mozl7XK+ROwTJ6QEJPo2XJ6uxWeuAmPE7ukMhgv4lj28oZSfE4wg==", "license": "MIT", "dependencies": { "accessor-fn": "1", @@ -5490,9 +5510,9 @@ } }, "node_modules/three-render-objects": { - "version": "1.40.2", - "resolved": "https://registry.npmjs.org/three-render-objects/-/three-render-objects-1.40.2.tgz", - "integrity": "sha512-4LAW9HJS1XcFN4+ujAWrcGAa3UalVTrtXzeWIR9hgJnYSCDBFgGzok9cDP9sXMlw5SjtDWkH6VOnGont+RzfSw==", + "version": "1.40.4", + "resolved": "https://registry.npmjs.org/three-render-objects/-/three-render-objects-1.40.4.tgz", + "integrity": "sha512-Ukpu1pei3L5r809izvjsZxwuRcYLiyn6Uvy3lZ9bpMTdvj3i6PeX6w++/hs2ZS3KnEzGjb6YvTvh4UQuwHTDJg==", "license": "MIT", "dependencies": { "@tweenjs/tween.js": "18 - 25", @@ -5509,9 +5529,9 @@ } }, "node_modules/three-spritetext": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/three-spritetext/-/three-spritetext-1.9.6.tgz", - "integrity": "sha512-+O5hGi6u4nWLefY8+Hlufd0aysWZhS2Ex61LCQVSixbYbykdPUOYYA+V+4xG4mKNDm1AsC0yHINRQS5NQb6mSg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/three-spritetext/-/three-spritetext-1.10.0.tgz", + "integrity": "sha512-t08iP1FCU1lQh8T5MmCpdijKgas8GDHJE0LqMGBuVu3xqMMpFnEZhTlih7FlxLPQizHIGoumUSpfOlY1GO/Tgg==", "license": "MIT", "engines": { "node": ">=12" @@ -5551,9 +5571,9 @@ } }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", "engines": { @@ -5591,9 +5611,9 @@ } }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5605,9 +5625,9 @@ } }, "node_modules/typo-js": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.5.tgz", - "integrity": "sha512-F45vFWdGX8xahIk/sOp79z2NJs8ETMYsmMChm9D5Hlx3+9j7VnCyQyvij5MOCrNY3NNe8noSyokRjQRfq+Bc7A==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.3.1.tgz", + "integrity": "sha512-elJkpCL6Z77Ghw0Lv0lGnhBAjSTOQ5FhiVOCfOuxhaoTT2xtLVbqikYItK5HHchzPbHEUFAcjOH669T2ZzeCbg==", "license": "BSD-3-Clause" }, "node_modules/ufo": { @@ -5811,13 +5831,13 @@ } }, "node_modules/vite-plugin-static-copy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.0.2.tgz", - "integrity": "sha512-/seLvhUg44s1oU9RhjTZZy/0NPbfNctozdysKcvPovxxXZdI5l19mGq6Ri3IaTf1Dy/qChS4BSR7ayxeu8o9aQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.1.2.tgz", + "integrity": "sha512-aVmYOzptLVOI2b1jL+cmkF7O6uhRv1u5fvOkQgbohWZp2CbR22kn9ZqkCUIt9umKF7UhdbsEpshn1rf4720QFg==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "fs-extra": "^11.3.0", "p-map": "^7.0.3", "picocolors": "^1.1.1", @@ -5827,7 +5847,7 @@ "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/vite-plugin-static-copy/node_modules/chokidar": { diff --git a/package.json b/package.json index 0e986ab9..eb600f26 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,9 @@ "@types/jquery": "^3.5.31", "@types/js-cookie": "^3.0.6", "typescript": "^5.8.3", - "vite": "^6.2.5", + "vite": "^6.2.6", "vite-bundle-visualizer": "^1.2.1", - "vite-plugin-static-copy": "^3.0.2" + "vite-plugin-static-copy": "^3.1.2" }, "dependencies": { "@alpinejs/sort": "^3.14.7", diff --git a/pyproject.toml b/pyproject.toml index e8ea292e..023be1e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,8 +43,8 @@ dependencies = [ "tomli<3.0.0,>=2.2.1", "django-honeypot>=1.3.0,<2", "pydantic-extra-types<3.0.0,>=2.10.3", - "ical>=10.0.3,<11", - "redis[hiredis]<6.0.0,>=5.3.0", + "ical>=11,<12", + "redis[hiredis]<7,>=5.3.0", "environs[django]<15.0.0,>=14.1.1", "requests>=2.32.3", "honcho>=2.0.0", @@ -63,7 +63,7 @@ prod = [ "psycopg[c]>=3.2.9,<4.0.0", ] dev = [ - "django-debug-toolbar>=5.2.0,<6.0.0", + "django-debug-toolbar>=6,<7", "ipython<10.0.0,>=9.0.2", "pre-commit<5.0.0,>=4.1.0", "ruff>=0.11.13,<1.0.0", @@ -78,7 +78,7 @@ tests = [ "pytest-django<5.0.0,>=4.10.0", "model-bakery<2.0.0,>=1.20.4", "beautifulsoup4>=4.13.3,<5", - "lxml>=5.3.1,<6", + "lxml>=6,<7", ] docs = [ "mkdocs<2.0.0,>=1.6.1", diff --git a/uv.lock b/uv.lock index 4b50121e..519cc848 100644 --- a/uv.lock +++ b/uv.lock @@ -492,15 +492,15 @@ wheels = [ [[package]] name = "django-debug-toolbar" -version = "5.2.0" +version = "6.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, { name = "sqlparse" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2a/9f/97ba2648f66fa208fc7f19d6895586d08bc5f0ab930a1f41032e60f31a41/django_debug_toolbar-5.2.0.tar.gz", hash = "sha256:9e7f0145e1a1b7d78fcc3b53798686170a5b472d9cf085d88121ff823e900821", size = 297901, upload-time = "2025-04-29T05:23:57.533Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/d5/5fc90234532088aeec5faa48d5b09951cc7eab6626030ed427d3bd8cd9bc/django_debug_toolbar-6.0.0.tar.gz", hash = "sha256:6eb9fa6f4a5884bf04004700ffb5a44043f1fff38784447fc52c1633448c8c14", size = 305331, upload-time = "2025-07-25T13:11:48.68Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/c2/ed3cb815002664349e9e50799b8c00ef15941f4cad797247cadbdeebab02/django_debug_toolbar-5.2.0-py3-none-any.whl", hash = "sha256:15627f4c2836a9099d795e271e38e8cf5204ccd79d5dbcd748f8a6c284dcd195", size = 262834, upload-time = "2025-04-29T05:23:55.472Z" }, + { url = "https://files.pythonhosted.org/packages/05/b5/4724a8c18fcc5b09dca7b7a0e70c34208317bb110075ad12484d6588ae91/django_debug_toolbar-6.0.0-py3-none-any.whl", hash = "sha256:0cf2cac5c307b77d6e143c914e5c6592df53ffe34642d93929e5ef095ae56841", size = 266967, upload-time = "2025-07-25T13:11:47.265Z" }, ] [[package]] @@ -776,17 +776,16 @@ wheels = [ [[package]] name = "ical" -version = "10.0.3" +version = "11.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, - { name = "pyparsing" }, { name = "python-dateutil" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/c2/4e9ee79dc0d9542c7758eed3eb92a95309cf022ea7187649427b163e1fcf/ical-10.0.3.tar.gz", hash = "sha256:bd318aa4cbdeaf3d161c8d676722690daa0e87a8c8553ae756f85bd54f60d2f0", size = 123230, upload-time = "2025-06-16T03:45:04.552Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/83/90976eec9a5146973aab21435b8997524b731a8b07b15d5911e088106131/ical-11.0.0.tar.gz", hash = "sha256:78efadc0711dc30da1392271c22713d3081a1df710eacac596f9d49f0030cc9d", size = 124045, upload-time = "2025-07-27T15:53:15.228Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/84/4b508115461cdec6510d31c6075d50d185c0097b377f437101f254d6a72e/ical-10.0.3-py3-none-any.whl", hash = "sha256:4b0804ce78dff206190b749c838866d286fff2a193a602b540f2c23ad149ea80", size = 122124, upload-time = "2025-06-16T03:45:03.025Z" }, + { url = "https://files.pythonhosted.org/packages/34/6b/9299af242cd6c98a57ab0dbc8634351900d470857e7b8d85f226ec57067b/ical-11.0.0-py3-none-any.whl", hash = "sha256:e22aa04010bc4e8621dd3503c5095087ca473450684a69527f37eabe91e145ea", size = 122728, upload-time = "2025-07-27T15:53:13.462Z" }, ] [[package]] @@ -921,44 +920,64 @@ wheels = [ [[package]] name = "lxml" -version = "5.4.0" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/76/3d/14e82fc7c8fb1b7761f7e748fd47e2ec8276d137b6acfe5a4bb73853e08f/lxml-5.4.0.tar.gz", hash = "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd", size = 3679479, upload-time = "2025-04-23T01:50:29.322Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/bd/f9d01fd4132d81c6f43ab01983caea69ec9614b913c290a26738431a015d/lxml-6.0.1.tar.gz", hash = "sha256:2b3a882ebf27dd026df3801a87cf49ff791336e0f94b0fad195db77e01240690", size = 4070214, upload-time = "2025-08-22T10:37:53.525Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/4c/d101ace719ca6a4ec043eb516fcfcb1b396a9fccc4fcd9ef593df34ba0d5/lxml-5.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4", size = 8127392, upload-time = "2025-04-23T01:46:04.09Z" }, - { url = "https://files.pythonhosted.org/packages/11/84/beddae0cec4dd9ddf46abf156f0af451c13019a0fa25d7445b655ba5ccb7/lxml-5.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d", size = 4415103, upload-time = "2025-04-23T01:46:07.227Z" }, - { url = "https://files.pythonhosted.org/packages/d0/25/d0d93a4e763f0462cccd2b8a665bf1e4343dd788c76dcfefa289d46a38a9/lxml-5.4.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779", size = 5024224, upload-time = "2025-04-23T01:46:10.237Z" }, - { url = "https://files.pythonhosted.org/packages/31/ce/1df18fb8f7946e7f3388af378b1f34fcf253b94b9feedb2cec5969da8012/lxml-5.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e", size = 4769913, upload-time = "2025-04-23T01:46:12.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/62/f4a6c60ae7c40d43657f552f3045df05118636be1165b906d3423790447f/lxml-5.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9", size = 5290441, upload-time = "2025-04-23T01:46:16.037Z" }, - { url = "https://files.pythonhosted.org/packages/9e/aa/04f00009e1e3a77838c7fc948f161b5d2d5de1136b2b81c712a263829ea4/lxml-5.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5", size = 4820165, upload-time = "2025-04-23T01:46:19.137Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/e0b2f61fa2404bf0f1fdf1898377e5bd1b74cc9b2cf2c6ba8509b8f27990/lxml-5.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5", size = 4932580, upload-time = "2025-04-23T01:46:21.963Z" }, - { url = "https://files.pythonhosted.org/packages/24/a2/8263f351b4ffe0ed3e32ea7b7830f845c795349034f912f490180d88a877/lxml-5.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4", size = 4759493, upload-time = "2025-04-23T01:46:24.316Z" }, - { url = "https://files.pythonhosted.org/packages/05/00/41db052f279995c0e35c79d0f0fc9f8122d5b5e9630139c592a0b58c71b4/lxml-5.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e", size = 5324679, upload-time = "2025-04-23T01:46:27.097Z" }, - { url = "https://files.pythonhosted.org/packages/1d/be/ee99e6314cdef4587617d3b3b745f9356d9b7dd12a9663c5f3b5734b64ba/lxml-5.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7", size = 4890691, upload-time = "2025-04-23T01:46:30.009Z" }, - { url = "https://files.pythonhosted.org/packages/ad/36/239820114bf1d71f38f12208b9c58dec033cbcf80101cde006b9bde5cffd/lxml-5.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079", size = 4955075, upload-time = "2025-04-23T01:46:32.33Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e1/1b795cc0b174efc9e13dbd078a9ff79a58728a033142bc6d70a1ee8fc34d/lxml-5.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20", size = 4838680, upload-time = "2025-04-23T01:46:34.852Z" }, - { url = "https://files.pythonhosted.org/packages/72/48/3c198455ca108cec5ae3662ae8acd7fd99476812fd712bb17f1b39a0b589/lxml-5.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8", size = 5391253, upload-time = "2025-04-23T01:46:37.608Z" }, - { url = "https://files.pythonhosted.org/packages/d6/10/5bf51858971c51ec96cfc13e800a9951f3fd501686f4c18d7d84fe2d6352/lxml-5.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f", size = 5261651, upload-time = "2025-04-23T01:46:40.183Z" }, - { url = "https://files.pythonhosted.org/packages/2b/11/06710dd809205377da380546f91d2ac94bad9ff735a72b64ec029f706c85/lxml-5.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc", size = 5024315, upload-time = "2025-04-23T01:46:43.333Z" }, - { url = "https://files.pythonhosted.org/packages/f5/b0/15b6217834b5e3a59ebf7f53125e08e318030e8cc0d7310355e6edac98ef/lxml-5.4.0-cp312-cp312-win32.whl", hash = "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f", size = 3486149, upload-time = "2025-04-23T01:46:45.684Z" }, - { url = "https://files.pythonhosted.org/packages/91/1e/05ddcb57ad2f3069101611bd5f5084157d90861a2ef460bf42f45cced944/lxml-5.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2", size = 3817095, upload-time = "2025-04-23T01:46:48.521Z" }, - { url = "https://files.pythonhosted.org/packages/87/cb/2ba1e9dd953415f58548506fa5549a7f373ae55e80c61c9041b7fd09a38a/lxml-5.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0", size = 8110086, upload-time = "2025-04-23T01:46:52.218Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3e/6602a4dca3ae344e8609914d6ab22e52ce42e3e1638c10967568c5c1450d/lxml-5.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de", size = 4404613, upload-time = "2025-04-23T01:46:55.281Z" }, - { url = "https://files.pythonhosted.org/packages/4c/72/bf00988477d3bb452bef9436e45aeea82bb40cdfb4684b83c967c53909c7/lxml-5.4.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76", size = 5012008, upload-time = "2025-04-23T01:46:57.817Z" }, - { url = "https://files.pythonhosted.org/packages/92/1f/93e42d93e9e7a44b2d3354c462cd784dbaaf350f7976b5d7c3f85d68d1b1/lxml-5.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d", size = 4760915, upload-time = "2025-04-23T01:47:00.745Z" }, - { url = "https://files.pythonhosted.org/packages/45/0b/363009390d0b461cf9976a499e83b68f792e4c32ecef092f3f9ef9c4ba54/lxml-5.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422", size = 5283890, upload-time = "2025-04-23T01:47:04.702Z" }, - { url = "https://files.pythonhosted.org/packages/19/dc/6056c332f9378ab476c88e301e6549a0454dbee8f0ae16847414f0eccb74/lxml-5.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551", size = 4812644, upload-time = "2025-04-23T01:47:07.833Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/f8c66bbb23ecb9048a46a5ef9b495fd23f7543df642dabeebcb2eeb66592/lxml-5.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c", size = 4921817, upload-time = "2025-04-23T01:47:10.317Z" }, - { url = "https://files.pythonhosted.org/packages/04/57/2e537083c3f381f83d05d9b176f0d838a9e8961f7ed8ddce3f0217179ce3/lxml-5.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff", size = 4753916, upload-time = "2025-04-23T01:47:12.823Z" }, - { url = "https://files.pythonhosted.org/packages/d8/80/ea8c4072109a350848f1157ce83ccd9439601274035cd045ac31f47f3417/lxml-5.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60", size = 5289274, upload-time = "2025-04-23T01:47:15.916Z" }, - { url = "https://files.pythonhosted.org/packages/b3/47/c4be287c48cdc304483457878a3f22999098b9a95f455e3c4bda7ec7fc72/lxml-5.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8", size = 4874757, upload-time = "2025-04-23T01:47:19.793Z" }, - { url = "https://files.pythonhosted.org/packages/2f/04/6ef935dc74e729932e39478e44d8cfe6a83550552eaa072b7c05f6f22488/lxml-5.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982", size = 4947028, upload-time = "2025-04-23T01:47:22.401Z" }, - { url = "https://files.pythonhosted.org/packages/cb/f9/c33fc8daa373ef8a7daddb53175289024512b6619bc9de36d77dca3df44b/lxml-5.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61", size = 4834487, upload-time = "2025-04-23T01:47:25.513Z" }, - { url = "https://files.pythonhosted.org/packages/8d/30/fc92bb595bcb878311e01b418b57d13900f84c2b94f6eca9e5073ea756e6/lxml-5.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54", size = 5381688, upload-time = "2025-04-23T01:47:28.454Z" }, - { url = "https://files.pythonhosted.org/packages/43/d1/3ba7bd978ce28bba8e3da2c2e9d5ae3f8f521ad3f0ca6ea4788d086ba00d/lxml-5.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b", size = 5242043, upload-time = "2025-04-23T01:47:31.208Z" }, - { url = "https://files.pythonhosted.org/packages/ee/cd/95fa2201041a610c4d08ddaf31d43b98ecc4b1d74b1e7245b1abdab443cb/lxml-5.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a", size = 5021569, upload-time = "2025-04-23T01:47:33.805Z" }, - { url = "https://files.pythonhosted.org/packages/2d/a6/31da006fead660b9512d08d23d31e93ad3477dd47cc42e3285f143443176/lxml-5.4.0-cp313-cp313-win32.whl", hash = "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82", size = 3485270, upload-time = "2025-04-23T01:47:36.133Z" }, - { url = "https://files.pythonhosted.org/packages/fc/14/c115516c62a7d2499781d2d3d7215218c0731b2c940753bf9f9b7b73924d/lxml-5.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f", size = 3814606, upload-time = "2025-04-23T01:47:39.028Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a9/82b244c8198fcdf709532e39a1751943a36b3e800b420adc739d751e0299/lxml-6.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c03ac546adaabbe0b8e4a15d9ad815a281afc8d36249c246aecf1aaad7d6f200", size = 8422788, upload-time = "2025-08-22T10:32:56.612Z" }, + { url = "https://files.pythonhosted.org/packages/c9/8d/1ed2bc20281b0e7ed3e6c12b0a16e64ae2065d99be075be119ba88486e6d/lxml-6.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33b862c7e3bbeb4ba2c96f3a039f925c640eeba9087a4dc7a572ec0f19d89392", size = 4593547, upload-time = "2025-08-22T10:32:59.016Z" }, + { url = "https://files.pythonhosted.org/packages/76/53/d7fd3af95b72a3493bf7fbe842a01e339d8f41567805cecfecd5c71aa5ee/lxml-6.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a3ec1373f7d3f519de595032d4dcafae396c29407cfd5073f42d267ba32440d", size = 4948101, upload-time = "2025-08-22T10:33:00.765Z" }, + { url = "https://files.pythonhosted.org/packages/9d/51/4e57cba4d55273c400fb63aefa2f0d08d15eac021432571a7eeefee67bed/lxml-6.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03b12214fb1608f4cffa181ec3d046c72f7e77c345d06222144744c122ded870", size = 5108090, upload-time = "2025-08-22T10:33:03.108Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6e/5f290bc26fcc642bc32942e903e833472271614e24d64ad28aaec09d5dae/lxml-6.0.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:207ae0d5f0f03b30f95e649a6fa22aa73f5825667fee9c7ec6854d30e19f2ed8", size = 5021791, upload-time = "2025-08-22T10:33:06.972Z" }, + { url = "https://files.pythonhosted.org/packages/13/d4/2e7551a86992ece4f9a0f6eebd4fb7e312d30f1e372760e2109e721d4ce6/lxml-6.0.1-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:32297b09ed4b17f7b3f448de87a92fb31bb8747496623483788e9f27c98c0f00", size = 5358861, upload-time = "2025-08-22T10:33:08.967Z" }, + { url = "https://files.pythonhosted.org/packages/8a/5f/cb49d727fc388bf5fd37247209bab0da11697ddc5e976ccac4826599939e/lxml-6.0.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e18224ea241b657a157c85e9cac82c2b113ec90876e01e1f127312006233756", size = 5652569, upload-time = "2025-08-22T10:33:10.815Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b8/66c1ef8c87ad0f958b0a23998851e610607c74849e75e83955d5641272e6/lxml-6.0.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a07a994d3c46cd4020c1ea566345cf6815af205b1e948213a4f0f1d392182072", size = 5252262, upload-time = "2025-08-22T10:33:12.673Z" }, + { url = "https://files.pythonhosted.org/packages/1a/ef/131d3d6b9590e64fdbb932fbc576b81fcc686289da19c7cb796257310e82/lxml-6.0.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:2287fadaa12418a813b05095485c286c47ea58155930cfbd98c590d25770e225", size = 4710309, upload-time = "2025-08-22T10:33:14.952Z" }, + { url = "https://files.pythonhosted.org/packages/bc/3f/07f48ae422dce44902309aa7ed386c35310929dc592439c403ec16ef9137/lxml-6.0.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b4e597efca032ed99f418bd21314745522ab9fa95af33370dcee5533f7f70136", size = 5265786, upload-time = "2025-08-22T10:33:16.721Z" }, + { url = "https://files.pythonhosted.org/packages/11/c7/125315d7b14ab20d9155e8316f7d287a4956098f787c22d47560b74886c4/lxml-6.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9696d491f156226decdd95d9651c6786d43701e49f32bf23715c975539aa2b3b", size = 5062272, upload-time = "2025-08-22T10:33:18.478Z" }, + { url = "https://files.pythonhosted.org/packages/8b/c3/51143c3a5fc5168a7c3ee626418468ff20d30f5a59597e7b156c1e61fba8/lxml-6.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e4e3cd3585f3c6f87cdea44cda68e692cc42a012f0131d25957ba4ce755241a7", size = 4786955, upload-time = "2025-08-22T10:33:20.34Z" }, + { url = "https://files.pythonhosted.org/packages/11/86/73102370a420ec4529647b31c4a8ce8c740c77af3a5fae7a7643212d6f6e/lxml-6.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:45cbc92f9d22c28cd3b97f8d07fcefa42e569fbd587dfdac76852b16a4924277", size = 5673557, upload-time = "2025-08-22T10:33:22.282Z" }, + { url = "https://files.pythonhosted.org/packages/d7/2d/aad90afaec51029aef26ef773b8fd74a9e8706e5e2f46a57acd11a421c02/lxml-6.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f8c9bcfd2e12299a442fba94459adf0b0d001dbc68f1594439bfa10ad1ecb74b", size = 5254211, upload-time = "2025-08-22T10:33:24.15Z" }, + { url = "https://files.pythonhosted.org/packages/63/01/c9e42c8c2d8b41f4bdefa42ab05448852e439045f112903dd901b8fbea4d/lxml-6.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1e9dc2b9f1586e7cd77753eae81f8d76220eed9b768f337dc83a3f675f2f0cf9", size = 5275817, upload-time = "2025-08-22T10:33:26.007Z" }, + { url = "https://files.pythonhosted.org/packages/bc/1f/962ea2696759abe331c3b0e838bb17e92224f39c638c2068bf0d8345e913/lxml-6.0.1-cp312-cp312-win32.whl", hash = "sha256:987ad5c3941c64031f59c226167f55a04d1272e76b241bfafc968bdb778e07fb", size = 3610889, upload-time = "2025-08-22T10:33:28.169Z" }, + { url = "https://files.pythonhosted.org/packages/41/e2/22c86a990b51b44442b75c43ecb2f77b8daba8c4ba63696921966eac7022/lxml-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:abb05a45394fd76bf4a60c1b7bec0e6d4e8dfc569fc0e0b1f634cd983a006ddc", size = 4010925, upload-time = "2025-08-22T10:33:29.874Z" }, + { url = "https://files.pythonhosted.org/packages/b2/21/dc0c73325e5eb94ef9c9d60dbb5dcdcb2e7114901ea9509735614a74e75a/lxml-6.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:c4be29bce35020d8579d60aa0a4e95effd66fcfce31c46ffddf7e5422f73a299", size = 3671922, upload-time = "2025-08-22T10:33:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/43/c4/cd757eeec4548e6652eff50b944079d18ce5f8182d2b2cf514e125e8fbcb/lxml-6.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:485eda5d81bb7358db96a83546949c5fe7474bec6c68ef3fa1fb61a584b00eea", size = 8405139, upload-time = "2025-08-22T10:33:34.09Z" }, + { url = "https://files.pythonhosted.org/packages/ff/99/0290bb86a7403893f5e9658490c705fcea103b9191f2039752b071b4ef07/lxml-6.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d12160adea318ce3d118f0b4fbdff7d1225c75fb7749429541b4d217b85c3f76", size = 4585954, upload-time = "2025-08-22T10:33:36.294Z" }, + { url = "https://files.pythonhosted.org/packages/88/a7/4bb54dd1e626342a0f7df6ec6ca44fdd5d0e100ace53acc00e9a689ead04/lxml-6.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48c8d335d8ab72f9265e7ba598ae5105a8272437403f4032107dbcb96d3f0b29", size = 4944052, upload-time = "2025-08-22T10:33:38.19Z" }, + { url = "https://files.pythonhosted.org/packages/71/8d/20f51cd07a7cbef6214675a8a5c62b2559a36d9303fe511645108887c458/lxml-6.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:405e7cf9dbdbb52722c231e0f1257214202dfa192327fab3de45fd62e0554082", size = 5098885, upload-time = "2025-08-22T10:33:40.035Z" }, + { url = "https://files.pythonhosted.org/packages/5a/63/efceeee7245d45f97d548e48132258a36244d3c13c6e3ddbd04db95ff496/lxml-6.0.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:299a790d403335a6a057ade46f92612ebab87b223e4e8c5308059f2dc36f45ed", size = 5017542, upload-time = "2025-08-22T10:33:41.896Z" }, + { url = "https://files.pythonhosted.org/packages/57/5d/92cb3d3499f5caba17f7933e6be3b6c7de767b715081863337ced42eb5f2/lxml-6.0.1-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:48da704672f6f9c461e9a73250440c647638cc6ff9567ead4c3b1f189a604ee8", size = 5347303, upload-time = "2025-08-22T10:33:43.868Z" }, + { url = "https://files.pythonhosted.org/packages/69/f8/606fa16a05d7ef5e916c6481c634f40870db605caffed9d08b1a4fb6b989/lxml-6.0.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:21e364e1bb731489e3f4d51db416f991a5d5da5d88184728d80ecfb0904b1d68", size = 5641055, upload-time = "2025-08-22T10:33:45.784Z" }, + { url = "https://files.pythonhosted.org/packages/b3/01/15d5fc74ebb49eac4e5df031fbc50713dcc081f4e0068ed963a510b7d457/lxml-6.0.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bce45a2c32032afddbd84ed8ab092130649acb935536ef7a9559636ce7ffd4a", size = 5242719, upload-time = "2025-08-22T10:33:48.089Z" }, + { url = "https://files.pythonhosted.org/packages/42/a5/1b85e2aaaf8deaa67e04c33bddb41f8e73d07a077bf9db677cec7128bfb4/lxml-6.0.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:fa164387ff20ab0e575fa909b11b92ff1481e6876835014e70280769920c4433", size = 4717310, upload-time = "2025-08-22T10:33:49.852Z" }, + { url = "https://files.pythonhosted.org/packages/42/23/f3bb1292f55a725814317172eeb296615db3becac8f1a059b53c51fc1da8/lxml-6.0.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7587ac5e000e1594e62278422c5783b34a82b22f27688b1074d71376424b73e8", size = 5254024, upload-time = "2025-08-22T10:33:52.22Z" }, + { url = "https://files.pythonhosted.org/packages/b4/be/4d768f581ccd0386d424bac615d9002d805df7cc8482ae07d529f60a3c1e/lxml-6.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:57478424ac4c9170eabf540237125e8d30fad1940648924c058e7bc9fb9cf6dd", size = 5055335, upload-time = "2025-08-22T10:33:54.041Z" }, + { url = "https://files.pythonhosted.org/packages/40/07/ed61d1a3e77d1a9f856c4fab15ee5c09a2853fb7af13b866bb469a3a6d42/lxml-6.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:09c74afc7786c10dd6afaa0be2e4805866beadc18f1d843cf517a7851151b499", size = 4784864, upload-time = "2025-08-22T10:33:56.382Z" }, + { url = "https://files.pythonhosted.org/packages/01/37/77e7971212e5c38a55431744f79dff27fd751771775165caea096d055ca4/lxml-6.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7fd70681aeed83b196482d42a9b0dc5b13bab55668d09ad75ed26dff3be5a2f5", size = 5657173, upload-time = "2025-08-22T10:33:58.698Z" }, + { url = "https://files.pythonhosted.org/packages/32/a3/e98806d483941cd9061cc838b1169626acef7b2807261fbe5e382fcef881/lxml-6.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:10a72e456319b030b3dd900df6b1f19d89adf06ebb688821636dc406788cf6ac", size = 5245896, upload-time = "2025-08-22T10:34:00.586Z" }, + { url = "https://files.pythonhosted.org/packages/07/de/9bb5a05e42e8623bf06b4638931ea8c8f5eb5a020fe31703abdbd2e83547/lxml-6.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0fa45fb5f55111ce75b56c703843b36baaf65908f8b8d2fbbc0e249dbc127ed", size = 5267417, upload-time = "2025-08-22T10:34:02.719Z" }, + { url = "https://files.pythonhosted.org/packages/f2/43/c1cb2a7c67226266c463ef8a53b82d42607228beb763b5fbf4867e88a21f/lxml-6.0.1-cp313-cp313-win32.whl", hash = "sha256:01dab65641201e00c69338c9c2b8a0f2f484b6b3a22d10779bb417599fae32b5", size = 3610051, upload-time = "2025-08-22T10:34:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/34/96/6a6c3b8aa480639c1a0b9b6faf2a63fb73ab79ffcd2a91cf28745faa22de/lxml-6.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:bdf8f7c8502552d7bff9e4c98971910a0a59f60f88b5048f608d0a1a75e94d1c", size = 4009325, upload-time = "2025-08-22T10:34:06.24Z" }, + { url = "https://files.pythonhosted.org/packages/8c/66/622e8515121e1fd773e3738dae71b8df14b12006d9fb554ce90886689fd0/lxml-6.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:a6aeca75959426b9fd8d4782c28723ba224fe07cfa9f26a141004210528dcbe2", size = 3670443, upload-time = "2025-08-22T10:34:07.974Z" }, + { url = "https://files.pythonhosted.org/packages/38/e3/b7eb612ce07abe766918a7e581ec6a0e5212352194001fd287c3ace945f0/lxml-6.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:29b0e849ec7030e3ecb6112564c9f7ad6881e3b2375dd4a0c486c5c1f3a33859", size = 8426160, upload-time = "2025-08-22T10:34:10.154Z" }, + { url = "https://files.pythonhosted.org/packages/35/8f/ab3639a33595cf284fe733c6526da2ca3afbc5fd7f244ae67f3303cec654/lxml-6.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:02a0f7e629f73cc0be598c8b0611bf28ec3b948c549578a26111b01307fd4051", size = 4589288, upload-time = "2025-08-22T10:34:12.972Z" }, + { url = "https://files.pythonhosted.org/packages/2c/65/819d54f2e94d5c4458c1db8c1ccac9d05230b27c1038937d3d788eb406f9/lxml-6.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:beab5e54de016e730875f612ba51e54c331e2fa6dc78ecf9a5415fc90d619348", size = 4964523, upload-time = "2025-08-22T10:34:15.474Z" }, + { url = "https://files.pythonhosted.org/packages/5b/4a/d4a74ce942e60025cdaa883c5a4478921a99ce8607fc3130f1e349a83b28/lxml-6.0.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a08aefecd19ecc4ebf053c27789dd92c87821df2583a4337131cf181a1dffa", size = 5101108, upload-time = "2025-08-22T10:34:17.348Z" }, + { url = "https://files.pythonhosted.org/packages/cb/48/67f15461884074edd58af17b1827b983644d1fae83b3d909e9045a08b61e/lxml-6.0.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36c8fa7e177649470bc3dcf7eae6bee1e4984aaee496b9ccbf30e97ac4127fa2", size = 5053498, upload-time = "2025-08-22T10:34:19.232Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d4/ec1bf1614828a5492f4af0b6a9ee2eb3e92440aea3ac4fa158e5228b772b/lxml-6.0.1-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:5d08e0f1af6916267bb7eff21c09fa105620f07712424aaae09e8cb5dd4164d1", size = 5351057, upload-time = "2025-08-22T10:34:21.143Z" }, + { url = "https://files.pythonhosted.org/packages/65/2b/c85929dacac08821f2100cea3eb258ce5c8804a4e32b774f50ebd7592850/lxml-6.0.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9705cdfc05142f8c38c97a61bd3a29581ceceb973a014e302ee4a73cc6632476", size = 5671579, upload-time = "2025-08-22T10:34:23.528Z" }, + { url = "https://files.pythonhosted.org/packages/d0/36/cf544d75c269b9aad16752fd9f02d8e171c5a493ca225cb46bb7ba72868c/lxml-6.0.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74555e2da7c1636e30bff4e6e38d862a634cf020ffa591f1f63da96bf8b34772", size = 5250403, upload-time = "2025-08-22T10:34:25.642Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e8/83dbc946ee598fd75fdeae6151a725ddeaab39bb321354a9468d4c9f44f3/lxml-6.0.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:e38b5f94c5a2a5dadaddd50084098dfd005e5a2a56cd200aaf5e0a20e8941782", size = 4696712, upload-time = "2025-08-22T10:34:27.753Z" }, + { url = "https://files.pythonhosted.org/packages/f4/72/889c633b47c06205743ba935f4d1f5aa4eb7f0325d701ed2b0540df1b004/lxml-6.0.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a5ec101a92ddacb4791977acfc86c1afd624c032974bfb6a21269d1083c9bc49", size = 5268177, upload-time = "2025-08-22T10:34:29.804Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b6/f42a21a1428479b66ea0da7bd13e370436aecaff0cfe93270c7e165bd2a4/lxml-6.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5c17e70c82fd777df586c12114bbe56e4e6f823a971814fd40dec9c0de518772", size = 5094648, upload-time = "2025-08-22T10:34:31.703Z" }, + { url = "https://files.pythonhosted.org/packages/51/b0/5f8c1e8890e2ee1c2053c2eadd1cb0e4b79e2304e2912385f6ca666f48b1/lxml-6.0.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:45fdd0415a0c3d91640b5d7a650a8f37410966a2e9afebb35979d06166fd010e", size = 4745220, upload-time = "2025-08-22T10:34:33.595Z" }, + { url = "https://files.pythonhosted.org/packages/eb/f9/820b5125660dae489ca3a21a36d9da2e75dd6b5ffe922088f94bbff3b8a0/lxml-6.0.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d417eba28981e720a14fcb98f95e44e7a772fe25982e584db38e5d3b6ee02e79", size = 5692913, upload-time = "2025-08-22T10:34:35.482Z" }, + { url = "https://files.pythonhosted.org/packages/23/8e/a557fae9eec236618aecf9ff35fec18df41b6556d825f3ad6017d9f6e878/lxml-6.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:8e5d116b9e59be7934febb12c41cce2038491ec8fdb743aeacaaf36d6e7597e4", size = 5259816, upload-time = "2025-08-22T10:34:37.482Z" }, + { url = "https://files.pythonhosted.org/packages/fa/fd/b266cfaab81d93a539040be699b5854dd24c84e523a1711ee5f615aa7000/lxml-6.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c238f0d0d40fdcb695c439fe5787fa69d40f45789326b3bb6ef0d61c4b588d6e", size = 5276162, upload-time = "2025-08-22T10:34:39.507Z" }, + { url = "https://files.pythonhosted.org/packages/25/6c/6f9610fbf1de002048e80585ea4719591921a0316a8565968737d9f125ca/lxml-6.0.1-cp314-cp314-win32.whl", hash = "sha256:537b6cf1c5ab88cfd159195d412edb3e434fee880f206cbe68dff9c40e17a68a", size = 3669595, upload-time = "2025-08-22T10:34:41.783Z" }, + { url = "https://files.pythonhosted.org/packages/72/a5/506775e3988677db24dc75a7b03e04038e0b3d114ccd4bccea4ce0116c15/lxml-6.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:911d0a2bb3ef3df55b3d97ab325a9ca7e438d5112c102b8495321105d25a441b", size = 4079818, upload-time = "2025-08-22T10:34:44.04Z" }, + { url = "https://files.pythonhosted.org/packages/0a/44/9613f300201b8700215856e5edd056d4e58dd23368699196b58877d4408b/lxml-6.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:2834377b0145a471a654d699bdb3a2155312de492142ef5a1d426af2c60a0a31", size = 3753901, upload-time = "2025-08-22T10:34:45.799Z" }, ] [[package]] @@ -1506,15 +1525,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/d1/c54e608505776ce4e7966d03358ae635cfd51dff1da6ee421c090dbc797b/pymdown_extensions-10.15-py3-none-any.whl", hash = "sha256:46e99bb272612b0de3b7e7caf6da8dd5f4ca5212c0b273feb9304e236c484e5f", size = 265845, upload-time = "2025-04-27T23:48:27.359Z" }, ] -[[package]] -name = "pyparsing" -version = "3.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" }, -] - [[package]] name = "pytest" version = "8.4.0" @@ -1826,7 +1836,7 @@ requires-dist = [ { name = "django-simple-captcha", specifier = ">=0.6.2,<1.0.0" }, { name = "environs", extras = ["django"], specifier = ">=14.1.1,<15.0.0" }, { name = "honcho", specifier = ">=2.0.0" }, - { name = "ical", specifier = ">=10.0.3,<11" }, + { name = "ical", specifier = ">=11,<12" }, { name = "jinja2", specifier = ">=3.1.6,<4.0.0" }, { name = "libsass", specifier = ">=0.23.0,<1.0.0" }, { name = "mistune", specifier = ">=3.1.3,<4.0.0" }, @@ -1835,7 +1845,7 @@ requires-dist = [ { name = "psutil", specifier = ">=7.0.0" }, { name = "pydantic-extra-types", specifier = ">=2.10.3,<3.0.0" }, { name = "python-dateutil", specifier = ">=2.9.0.post0,<3.0.0.0" }, - { name = "redis", extras = ["hiredis"], specifier = ">=5.3.0,<6.0.0" }, + { name = "redis", extras = ["hiredis"], specifier = ">=5.3.0,<7" }, { name = "reportlab", specifier = ">=4.3.1,<5.0.0" }, { name = "requests", specifier = ">=2.32.3" }, { name = "sentry-sdk", specifier = ">=2.25.1,<3.0.0" }, @@ -1846,7 +1856,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "django-debug-toolbar", specifier = ">=5.2.0,<6.0.0" }, + { name = "django-debug-toolbar", specifier = ">=6,<7" }, { name = "djhtml", specifier = ">=3.0.7,<4.0.0" }, { name = "faker", specifier = ">=37.0.0,<38.0.0" }, { name = "ipython", specifier = ">=9.0.2,<10.0.0" }, @@ -1865,7 +1875,7 @@ prod = [{ name = "psycopg", extras = ["c"], specifier = ">=3.2.9,<4.0.0" }] tests = [ { name = "beautifulsoup4", specifier = ">=4.13.3,<5" }, { name = "freezegun", specifier = ">=1.5.1,<2.0.0" }, - { name = "lxml", specifier = ">=5.3.1,<6" }, + { name = "lxml", specifier = ">=6,<7" }, { name = "model-bakery", specifier = ">=1.20.4,<2.0.0" }, { name = "pytest", specifier = ">=8.3.5,<9.0.0" }, { name = "pytest-cov", specifier = ">=6.0.0,<7.0.0" }, From d8f907fc700fe4f09e1fb3ddf1ef2cd759b28bc6 Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 26 Feb 2025 23:25:07 +0100 Subject: [PATCH 12/14] Optimize galaxy generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En réorganisant les requêtes à la db, on diminue par 100 le temps d'exécution de la commande `rule_galaxy` (~6h => ~2min) --- galaxy/models.py | 359 +++++++++++++++++------------------------------ galaxy/tests.py | 46 +++--- 2 files changed, 155 insertions(+), 250 deletions(-) diff --git a/galaxy/models.py b/galaxy/models.py index f306884d..438d37bc 100644 --- a/galaxy/models.py +++ b/galaxy/models.py @@ -23,20 +23,21 @@ from __future__ import annotations +import itertools import logging import math import time +from collections import defaultdict from typing import NamedTuple, TypedDict from django.db import models -from django.db.models import Case, Count, F, Q, Value, When -from django.db.models.functions import Concat +from django.db.models import Count, F, Q, QuerySet from django.utils.timezone import localdate from django.utils.translation import gettext_lazy as _ -from club.models import Club +from club.models import Membership from core.models import User -from sas.models import Picture +from sas.models import PeoplePictureRelation, Picture class GalaxyStar(models.Model): @@ -114,18 +115,9 @@ class GalaxyLane(models.Model): default=0, help_text=_("Distance separating star1 and star2"), ) - family = models.PositiveIntegerField( - _("family score"), - default=0, - ) - pictures = models.PositiveIntegerField( - _("pictures score"), - default=0, - ) - clubs = models.PositiveIntegerField( - _("clubs score"), - default=0, - ) + family = models.PositiveIntegerField(_("family score"), default=0) + pictures = models.PositiveIntegerField(_("pictures score"), default=0) + clubs = models.PositiveIntegerField(_("clubs score"), default=0) def __str__(self): return f"{self.star1} -> {self.star2} ({self.distance})" @@ -174,6 +166,7 @@ class Galaxy(models.Model): logger = logging.getLogger("main") GALAXY_SCALE_FACTOR = 2_000 + DEFAULT_PICTURE_COUNT_THRESHOLD = 10 FAMILY_LINK_POINTS = 366 # Equivalent to a leap year together in a club, because. PICTURE_POINTS = 2 # Equivalent to two days as random members of a club. CLUBS_POINTS = 1 # One day together as random members in a club is one point. @@ -187,15 +180,13 @@ class Galaxy(models.Model): stars_count = self.stars.count() s = f"GLX-ID{self.pk}-SC{stars_count}-" if self.state is None: - s += "CHS" # CHAOS + s += "CHAOS" else: - s += "RLD" # RULED + s += "RULED" return s @classmethod - def get_current_galaxy( - cls, - ) -> Galaxy: # __future__.annotations is required for this + def get_current_galaxy(cls) -> Galaxy: return Galaxy.objects.filter(state__isnull=False).last() ################### @@ -203,7 +194,18 @@ class Galaxy(models.Model): ################### @classmethod - def compute_user_score(cls, user: User) -> int: + def get_rulable_users( + cls, picture_count_threshold: int = DEFAULT_PICTURE_COUNT_THRESHOLD + ) -> QuerySet[User]: + return ( + User.objects.exclude(subscriptions=None) + .annotate(pictures_count=Count("pictures")) + .filter(pictures_count__gt=picture_count_threshold) + .distinct() + ) + + @classmethod + def compute_individual_scores(cls) -> dict[int, int]: """Compute an individual score for each citizen. It will later be used by the graph algorithm to push @@ -211,87 +213,50 @@ class Galaxy(models.Model): Idea: This could be added to the computation: - - Forum posts - Picture count - Counter consumption - Barman time - ... """ - user_score = 1 - user_score += cls.query_user_score(user) - + users = ( + User.objects.annotate( + score=( + Count("godchildren", distinct=True) * cls.FAMILY_LINK_POINTS + + Count("godfathers", distinct=True) * cls.FAMILY_LINK_POINTS + + Count("pictures", distinct=True) * cls.PICTURE_POINTS + + Count("memberships", distinct=True) * cls.CLUBS_POINTS + ) + ) + .filter(score__gt=0) + .values("id", "score") + ) # TODO: # Scale that value with some magic number to accommodate to typical data # Really active galaxy citizen after 5 years typically have a score of about XXX # Citizen that were seen regularly without taking much part in organizations typically have a score of about XXX # Citizen that only went to a few events typically score about XXX - user_score = int(math.log2(user_score)) - - return user_score - - @classmethod - def query_user_score(cls, user: User) -> int: - """Get the individual score of the given user in the galaxy.""" - score_query = ( - User.objects.filter(id=user.id) - .annotate( - godchildren_count=Count("godchildren", distinct=True) - * cls.FAMILY_LINK_POINTS, - godfathers_count=Count("godfathers", distinct=True) - * cls.FAMILY_LINK_POINTS, - pictures_score=Count("pictures", distinct=True) * cls.PICTURE_POINTS, - clubs_score=Count("memberships", distinct=True) * cls.CLUBS_POINTS, - ) - .aggregate( - score=models.Sum( - F("godchildren_count") - + F("godfathers_count") - + F("pictures_score") - + F("clubs_score") - ) - ) - ) - return score_query.get("score") + res = {u["id"]: int(math.log2(u["score"] + 1)) for u in users} + return res #################### # Inter-user score # #################### @classmethod - def compute_users_score(cls, user1: User, user2: User) -> RelationScore: - """Compute the relationship scores of the two given users. - - The computation is done with the following fields : - - - family: if they have some godfather/godchild relation - - pictures: in how many pictures are both tagged - - clubs: during how many days they were members of the same clubs - """ - family = cls.compute_users_family_score(user1, user2) - pictures = cls.compute_users_pictures_score(user1, user2) - clubs = cls.compute_users_clubs_score(user1, user2) - return RelationScore(family=family, pictures=pictures, clubs=clubs) - - @classmethod - def compute_users_family_score(cls, user1: User, user2: User) -> int: + def compute_user_family_score(cls, user: User) -> defaultdict[int, int]: """Compute the family score of the relation between the given users. This takes into account mutual godfathers. - - Returns: - 366 if user1 is the godfather of user2 (or vice versa) else 0 """ - link_count = User.objects.filter( - Q(id=user1.id, godfathers=user2) | Q(id=user2.id, godfathers=user1) - ).count() - if link_count > 0: - cls.logger.debug( - f"\t\t- '{user1}' and '{user2}' have {link_count} direct family link" - ) - return link_count * cls.FAMILY_LINK_POINTS + godchildren = User.objects.filter(godchildren=user).values_list("id", flat=True) + godfathers = User.objects.filter(godfathers=user).values_list("id", flat=True) + result = defaultdict(int) + for parent in itertools.chain(godchildren, godfathers): + result[parent] += cls.FAMILY_LINK_POINTS + return result @classmethod - def compute_users_pictures_score(cls, user1: User, user2: User) -> int: + def compute_user_pictures_score(cls, user: User) -> defaultdict[int, int]: """Compute the pictures score of the relation between the given users. The pictures score is obtained by counting the number @@ -301,19 +266,19 @@ class Galaxy(models.Model): Returns: The number of pictures both users have in common, times 2 """ - picture_count = ( - Picture.objects.filter(people__user__in=(user1,)) - .filter(people__user__in=(user2,)) - .count() - ) - if picture_count: - cls.logger.debug( - f"\t\t- '{user1}' was pictured with '{user2}' {picture_count} times" + common_photos = ( + PeoplePictureRelation.objects.filter( + picture__in=Picture.objects.filter(people__user=user) ) - return picture_count * cls.PICTURE_POINTS + .values("user") + .annotate(count=Count("user")) + ) + return defaultdict( + int, {p["user"]: p["count"] * cls.PICTURE_POINTS for p in common_photos} + ) @classmethod - def compute_users_clubs_score(cls, user1: User, user2: User) -> int: + def compute_user_clubs_score(cls, user: User) -> defaultdict[int, int]: """Compute the clubs score of the relation between the given users. The club score is obtained by counting the number of days @@ -324,54 +289,36 @@ class Galaxy(models.Model): (two years) and user2 was a member of the same club from 01/01/2021 to 31/12/2022 (also two years, but with an offset of one year), then their club score is 365. - - Returns: - the number of days during which both users were in the same club """ - common_clubs = Club.objects.filter(members__in=user1.memberships.all()).filter( - members__in=user2.memberships.all() - ) - user1_memberships = user1.memberships.filter(club__in=common_clubs) - user2_memberships = user2.memberships.filter(club__in=common_clubs) - - score = 0 - for user1_membership in user1_memberships: - if user1_membership.end_date is None: - # user1_membership.save() is not called in this function, hence this is safe - user1_membership.end_date = localdate() - query = Q( # start2 <= start1 <= end2 - start_date__lte=user1_membership.start_date, - end_date__gte=user1_membership.start_date, - ) - query |= Q( # start2 <= start1 <= now - start_date__lte=user1_membership.start_date, end_date=None - ) - query |= Q( # start1 <= start2 <= end2 - start_date__gte=user1_membership.start_date, - start_date__lte=user1_membership.end_date, - ) - for user2_membership in user2_memberships.filter( - query, club=user1_membership.club - ): - if user2_membership.end_date is None: - user2_membership.end_date = localdate() - latest_start = max( - user1_membership.start_date, user2_membership.start_date - ) - earliest_end = min(user1_membership.end_date, user2_membership.end_date) - cls.logger.debug( - "\t\t- '%s' was with '%s' in %s starting on %s until %s (%s days)" - % ( - user1, - user2, - user2_membership.club, - latest_start, - earliest_end, - (earliest_end - latest_start).days, + memberships = user.memberships.only("start_date", "end_date", "club_id") + result = defaultdict(int) + now = localdate() + for membership in memberships: + # This is a N+1 query, but 92% of galaxy users have less than 10 memberships. + # Only 5 users have more than 30 memberships. + common_memberships = ( + Membership.objects.exclude(user=user) + .filter( + Q( # start2 <= start1 <= end2 + start_date__lte=membership.start_date, + end_date__gte=membership.start_date, ) + | Q( # start2 <= start1 <= now + start_date__lte=membership.start_date, end_date=None + ) + | Q( # start1 <= start2 <= end2 + start_date__gte=membership.start_date, + start_date__lte=membership.end_date or now, + ), + club_id=membership.club_id, ) - score += cls.CLUBS_POINTS * (earliest_end - latest_start).days - return score + .only("start_date", "end_date", "user_id") + ) + for other in common_memberships: + start = max(membership.start_date, other.start_date) + end = min(membership.end_date or now, other.end_date or now) + result[other.user_id] += (end - start).days * cls.CLUBS_POINTS + return result ################### # Rule the galaxy # @@ -406,7 +353,9 @@ class Galaxy(models.Model): cls.logger.debug(f"\t\t> Scaled distance: {value}") return int(value) - def rule(self, picture_count_threshold=10) -> None: + def rule( + self, picture_count_threshold: int = DEFAULT_PICTURE_COUNT_THRESHOLD + ) -> None: """Main function of the Galaxy. Iterate over all the rulable users to promote them to citizens. @@ -427,41 +376,30 @@ class Galaxy(models.Model): """ total_time = time.time() self.logger.info("Listing rulable citizen.") - rulable_users = ( - User.objects.filter(subscriptions__isnull=False) - .annotate(pictures_count=Count("pictures")) - .filter(pictures_count__gt=picture_count_threshold) - .distinct() - ) # force fetch of the whole query to make sure there won't # be any more db hits # this is memory expensive but prevents a lot of db hits, therefore # is far more time efficient - rulable_users = list(rulable_users) + rulable_users = list(self.get_rulable_users(picture_count_threshold)) rulable_users_count = len(rulable_users) user1_count = 0 self.logger.info( f"{rulable_users_count} citizen have been listed. Starting to rule." ) - stars = [] self.logger.info("Creating stars for all citizen") - for user in rulable_users: - star = GalaxyStar( - owner=user, galaxy=self, mass=self.compute_user_score(user) - ) - stars.append(star) - GalaxyStar.objects.bulk_create(stars) - - stars = {} - for star in GalaxyStar.objects.filter(galaxy=self): - stars[star.owner.id] = star + individual_scores = self.compute_individual_scores() + GalaxyStar.objects.bulk_create( + [ + GalaxyStar(owner=user, galaxy=self, mass=individual_scores[user.id]) + for user in rulable_users + ] + ) + stars = {star.owner_id: star for star in self.stars.all()} self.logger.info("Creating lanes between stars") - # Display current speed every $speed_count_frequency users - speed_count_frequency = max(rulable_users_count // 10, 1) # ten time at most global_avg_speed_accumulator = 0 global_avg_speed_count = 0 t_global_start = time.time() @@ -472,20 +410,19 @@ class Galaxy(models.Model): star1 = stars[user1.id] - user_avg_speed = 0 - user_avg_speed_count = 0 - - tstart = time.time() lanes = [] - for user2_count, user2 in enumerate(rulable_users, start=1): - self.logger.debug("") - self.logger.debug( - f"\t> Examining '{user1}' ({user1_count}/{rulable_users_count}) with '{user2}' ({user2_count}/{rulable_users_count2})" - ) + family_scores = self.compute_user_family_score(user1) + picture_scores = self.compute_user_pictures_score(user1) + club_scores = self.compute_user_clubs_score(user1) + for user2 in rulable_users: star2 = stars[user2.id] - score = Galaxy.compute_users_score(user1, user2) + score = RelationScore( + family=family_scores.get(user2.id, 0), + pictures=picture_scores.get(user2.id, 0), + clubs=club_scores.get(user2.id, 0), + ) distance = self.scale_distance(sum(score)) if distance < 30: # TODO: this needs tuning with real-world data lanes.append( @@ -498,22 +435,8 @@ class Galaxy(models.Model): clubs=score.clubs, ) ) - - if user2_count % speed_count_frequency == 0: - tend = time.time() - delta = tend - tstart - speed = float(speed_count_frequency) / delta - user_avg_speed += speed - user_avg_speed_count += 1 - self.logger.debug( - f"\tSpeed: {speed:.2f} users per second (time for last {speed_count_frequency} citizens: {delta:.2f} second)" - ) - tstart = time.time() - GalaxyLane.objects.bulk_create(lanes) - self.logger.info("") - t_global_end = time.time() global_delta = t_global_end - t_global_start speed = 1.0 / global_delta @@ -521,21 +444,19 @@ class Galaxy(models.Model): global_avg_speed_count += 1 global_avg_speed = global_avg_speed_accumulator / global_avg_speed_count - self.logger.info(f" Ruling of {self} ".center(60, "#")) - self.logger.info( - f"Progression: {user1_count}/{rulable_users_count} citizen -- {rulable_users_count - user1_count} remaining" - ) - self.logger.info(f"Speed: {60.0 * global_avg_speed:.2f} citizen per minute") - - # We can divide the computed ETA by 2 because each loop, there is one citizen less to check, and maths tell - # us that this averages to a division by two - eta = rulable_users_count2 / global_avg_speed / 2 - eta_hours = int(eta // 3600) - eta_minutes = int(eta // 60 % 60) - self.logger.info( - f"ETA: {eta_hours} hours {eta_minutes} minutes ({eta / 3600 / 24:.2f} days)" - ) - self.logger.info("#" * 60) + if user1_count % 50 == 0: + self.logger.info("") + self.logger.info(f" Ruling of {self} ".center(60, "#")) + self.logger.info( + f"Progression: {user1_count}/{rulable_users_count} " + f"citizen -- {rulable_users_count - user1_count} remaining" + ) + self.logger.info(f"Speed: {global_avg_speed:.2f} citizen per second") + eta = rulable_users_count2 // global_avg_speed + self.logger.info( + f"ETA: {int(eta // 60 % 60)} minutes {int(eta % 60)} seconds" + ) + self.logger.info("#" * 60) t_global_start = time.time() # Here, we get the IDs of the old galaxies that we'll need to delete. In normal operation, only one galaxy @@ -556,11 +477,10 @@ class Galaxy(models.Model): Galaxy.objects.filter(pk__in=old_galaxies_pks).delete() total_time = time.time() - total_time - total_time_hours = int(total_time // 3600) total_time_minutes = int(total_time // 60 % 60) total_time_seconds = int(total_time % 60) self.logger.info( - f"{self} ruled in {total_time:.2f} seconds ({total_time_hours} hours, {total_time_minutes} minutes, {total_time_seconds} seconds)" + f"{self} ruled in {total_time_minutes} minutes, {total_time_seconds} seconds" ) def make_state(self) -> None: @@ -568,59 +488,34 @@ class Galaxy(models.Model): self.logger.info( "Caching current Galaxy state for a quicker display of the Empire's power." ) - - without_nickname = Concat( - F("owner__first_name"), Value(" "), F("owner__last_name") - ) - with_nickname = Concat( - F("owner__first_name"), - Value(" "), - F("owner__last_name"), - Value(" ("), - F("owner__nick_name"), - Value(")"), - ) stars = ( GalaxyStar.objects.filter(galaxy=self) - .order_by( - "owner" - ) # This helps determinism for the tests and doesn't cost much - .annotate( - owner_name=Case( - When(owner__nick_name=None, then=without_nickname), - default=with_nickname, - ) - ) + .order_by("owner_id") + .select_related("owner") ) lanes = ( GalaxyLane.objects.filter(star1__galaxy=self) - .order_by( - "star1" - ) # This helps determinism for the tests and doesn't cost much + .order_by("star1") .annotate( - star1_owner=F("star1__owner__id"), - star2_owner=F("star2__owner__id"), + star1_owner=F("star1__owner_id"), star2_owner=F("star2__owner_id") ) ) json = GalaxyDict( nodes=[ StarDict( - id=star.owner_id, - name=star.owner_name, - mass=star.mass, + id=star.owner_id, name=star.owner.get_display_name(), mass=star.mass ) for star in stars ], - links=[], - ) - for path in lanes: - json["links"].append( + links=[ { "source": path.star1_owner, "target": path.star2_owner, "value": path.distance, } - ) + for path in lanes + ], + ) self.state = json self.save() self.logger.info(f"{self} is now ready!") diff --git a/galaxy/tests.py b/galaxy/tests.py index fc92fe9e..9c31acf2 100644 --- a/galaxy/tests.py +++ b/galaxy/tests.py @@ -33,7 +33,7 @@ from core.models import User from galaxy.models import Galaxy -@pytest.mark.skip(reason="Galaxy is disabled for now") +# @pytest.mark.skip(reason="Galaxy is disabled for now") class TestGalaxyModel(TestCase): @classmethod def setUpTestData(cls): @@ -48,15 +48,19 @@ class TestGalaxyModel(TestCase): def test_user_self_score(self): """Test that individual user scores are correct.""" - with self.assertNumQueries(8): - assert Galaxy.compute_user_score(self.root) == 9 - assert Galaxy.compute_user_score(self.skia) == 10 - assert Galaxy.compute_user_score(self.sli) == 8 - assert Galaxy.compute_user_score(self.krophil) == 2 - assert Galaxy.compute_user_score(self.richard) == 10 - assert Galaxy.compute_user_score(self.subscriber) == 8 - assert Galaxy.compute_user_score(self.public) == 8 - assert Galaxy.compute_user_score(self.com) == 1 + with self.assertNumQueries(1): + scores = Galaxy.compute_individual_scores() + expected = { + self.root.id: 9, + self.skia.id: 10, + self.sli.id: 8, + self.krophil.id: 2, + self.richard.id: 10, + self.subscriber.id: 8, + self.public.id: 8, + self.com.id: 1, + } + assert scores.items() >= expected.items() def test_users_score(self): """Test on the default dataset generated by the `populate` command @@ -118,17 +122,23 @@ class TestGalaxyModel(TestCase): self.com, ] - with self.assertNumQueries(100): + with self.assertNumQueries(44): while len(users) > 0: user1 = users.pop(0) + family_scores = Galaxy.compute_user_family_score(user1) + picture_scores = Galaxy.compute_user_pictures_score(user1) + club_scores = Galaxy.compute_user_clubs_score(user1) for user2 in users: - score = Galaxy.compute_users_score(user1, user2) u1 = computed_scores.get(user1.username, {}) u1[user2.username] = { - "score": sum(score), - "family": score.family, - "pictures": score.pictures, - "clubs": score.clubs, + "score": ( + family_scores[user2.id] + + picture_scores[user2.id] + + club_scores[user2.id] + ), + "family": family_scores[user2.id], + "pictures": picture_scores[user2.id], + "clubs": club_scores[user2.id], } computed_scores[user1.username] = u1 @@ -140,12 +150,12 @@ class TestGalaxyModel(TestCase): that the number of queries to rule the galaxy is stable. """ galaxy = Galaxy.objects.create() - with self.assertNumQueries(58): + with self.assertNumQueries(39): galaxy.rule(0) # We want everybody here @pytest.mark.slow -@pytest.mark.skip(reason="Galaxy is disabled for now") +# @pytest.mark.skip(reason="Galaxy is disabled for now") class TestGalaxyView(TestCase): @classmethod def setUpTestData(cls): From 2086d23b5065fe9d13ae0bb9910c5bc984068c70 Mon Sep 17 00:00:00 2001 From: imperosol Date: Sun, 31 Aug 2025 20:37:44 +0200 Subject: [PATCH 13/14] fix old subscribers group attribution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Si un utilisateur faisait sa première cotisation alors qu'il avait déjà un compte AE (par exemple, en effectuant un achat sur l'eboutic avant sa cotisation), alors il pouvait se retrouver hors du groupe Anciens cotisants. --- subscription/models.py | 21 +++++++------------ ...sbcription.py => test_new_subscription.py} | 19 ++++++++++++++++- subscription/views.py | 15 ++++++++++++- 3 files changed, 40 insertions(+), 15 deletions(-) rename subscription/tests/{test_new_susbcription.py => test_new_subscription.py} (89%) diff --git a/subscription/models.py b/subscription/models.py index 38d6c0f5..1d182ad0 100644 --- a/subscription/models.py +++ b/subscription/models.py @@ -18,7 +18,6 @@ from datetime import date, timedelta from dateutil.relativedelta import relativedelta from django.conf import settings -from django.contrib.auth.forms import PasswordResetForm from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse @@ -73,23 +72,19 @@ class Subscription(models.Model): return f"No user - {self.pk}" def save(self, *args, **kwargs): - super().save() from counter.models import Customer - _, account_created = Customer.get_or_create(self.member) - if account_created: + if not self.member.was_subscribed: + # This is the first ever subscription for this user + customer, _ = Customer.get_or_create(self.member) # Someone who subscribed once will be considered forever # as an old subscriber. self.member.groups.add(settings.SITH_GROUP_OLD_SUBSCRIBERS_ID) - form = PasswordResetForm({"email": self.member.email}) - if form.is_valid(): - form.save( - use_https=True, - email_template_name="core/new_user_email.jinja", - subject_template_name="core/new_user_email_subject.jinja", - from_email="ae@utbm.fr", - ) - self.member.make_home() + self.member.make_home() + # now that the user is an old subscriber, change the cached + # property accordingly + self.member.__dict__["was_subscribed"] = True + super().save() def get_absolute_url(self): return reverse("core:user_edit", kwargs={"user_id": self.member_id}) diff --git a/subscription/tests/test_new_susbcription.py b/subscription/tests/test_new_subscription.py similarity index 89% rename from subscription/tests/test_new_susbcription.py rename to subscription/tests/test_new_subscription.py index fd23d9dd..1c4eaa6b 100644 --- a/subscription/tests/test_new_susbcription.py +++ b/subscription/tests/test_new_subscription.py @@ -5,6 +5,7 @@ from typing import Callable import pytest from dateutil.relativedelta import relativedelta +from django.conf import settings from django.contrib.auth.models import Permission from django.test import Client from django.urls import reverse @@ -14,8 +15,10 @@ from pytest_django.asserts import assertRedirects from pytest_django.fixtures import SettingsWrapper from core.baker_recipes import board_user, old_subscriber_user, subscriber_user -from core.models import User +from core.models import Group, User +from counter.models import Customer from subscription.forms import SubscriptionExistingUserForm, SubscriptionNewUserForm +from subscription.models import Subscription @pytest.mark.django_db @@ -189,3 +192,17 @@ def test_submit_form_new_user(client: Client, settings: SettingsWrapper): kwargs={"subscription_id": current_subscription.id}, ), ) + + +@pytest.mark.django_db +def test_subscription_for_user_that_had_a_sith_account(): + """Test that a newly subscribed user is added to the old subscribers group, + even if there already was a sith account (e.g. created during an eboutic purchase). + """ + user = baker.make(User) + Customer.get_or_create(user) + group = Group.objects.get(id=settings.SITH_GROUP_OLD_SUBSCRIBERS_ID) + assert not user.groups.contains(group) + subscription = baker.prepare(Subscription, member=user) + subscription.save() + assert user.groups.contains(group) diff --git a/subscription/views.py b/subscription/views.py index d5f9d75d..035f9035 100644 --- a/subscription/views.py +++ b/subscription/views.py @@ -14,6 +14,7 @@ # from django.conf import settings +from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import PermissionDenied from django.urls import reverse, reverse_lazy @@ -65,11 +66,23 @@ class CreateSubscriptionExistingUserFragment(CreateSubscriptionFragment): class CreateSubscriptionNewUserFragment(CreateSubscriptionFragment): - """Create a subscription for a user who already exists.""" + """Create a subscription for a user who doesn't exist yet.""" form_class = SubscriptionNewUserForm extra_context = {"post_url": reverse_lazy("subscription:fragment-new-user")} + def form_valid(self, form): + res = super().form_valid(form) + reset_form = PasswordResetForm({"email": form.cleaned_data["email"]}) + if reset_form.is_valid(): + reset_form.save( + use_https=True, + email_template_name="core/new_user_email.jinja", + subject_template_name="core/new_user_email_subject.jinja", + from_email="ae@utbm.fr", + ) + return res + class SubscriptionCreatedFragment(PermissionRequiredMixin, DetailView): template_name = "subscription/fragments/creation_success.jinja" From 8524996f06a52d31cbbb0bb4ae5e72eb0adc23b8 Mon Sep 17 00:00:00 2001 From: imperosol Date: Mon, 1 Sep 2025 15:30:39 +0200 Subject: [PATCH 14/14] simplify `Subscription.save()` --- subscription/models.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/subscription/models.py b/subscription/models.py index 1d182ad0..e8aa4ff7 100644 --- a/subscription/models.py +++ b/subscription/models.py @@ -71,19 +71,21 @@ class Subscription(models.Model): else: return f"No user - {self.pk}" - def save(self, *args, **kwargs): + def save(self, *args, **kwargs) -> None: + if self.member.was_subscribed: + super().save() + return + from counter.models import Customer - if not self.member.was_subscribed: - # This is the first ever subscription for this user - customer, _ = Customer.get_or_create(self.member) - # Someone who subscribed once will be considered forever - # as an old subscriber. - self.member.groups.add(settings.SITH_GROUP_OLD_SUBSCRIBERS_ID) - self.member.make_home() - # now that the user is an old subscriber, change the cached - # property accordingly - self.member.__dict__["was_subscribed"] = True + customer, _ = Customer.get_or_create(self.member) + # Someone who subscribed once will be considered forever + # as an old subscriber. + self.member.groups.add(settings.SITH_GROUP_OLD_SUBSCRIBERS_ID) + self.member.make_home() + # now that the user is an old subscriber, change the cached + # property accordingly + self.member.__dict__["was_subscribed"] = True super().save() def get_absolute_url(self):