diff --git a/.github/workflows/apcd-cms.yml b/.github/workflows/apcd-cms.yml index a46a580b..90c86e0d 100644 --- a/.github/workflows/apcd-cms.yml +++ b/.github/workflows/apcd-cms.yml @@ -36,4 +36,4 @@ jobs: with: context: apcd_cms push: true - tags: taccwma/apcd-cms:${{ steps.vars.outputs.SHORT_SHA }},taccwma/apcd-cms:${{ steps.vars.outputs.BRANCH_NAME }} + tags: taccwma/apcd-cms:${{ steps.vars.outputs.SHORT_SHA }},taccwma/apcd-cms:${{ steps.vars.outputs.BRANCH_NAME }} \ No newline at end of file diff --git a/apcd_cms/Dockerfile b/apcd_cms/Dockerfile index 2d1d6b33..869035c5 100644 --- a/apcd_cms/Dockerfile +++ b/apcd_cms/Dockerfile @@ -1,7 +1,17 @@ -FROM taccwma/core-cms:v4.12.0 +# TACC/Core-CMS#v4.20.0 & TACC/Core-Styles#v2.37.0 +FROM taccwma/core-cms:v4.20.0 WORKDIR /code COPY /src/apps /code/apps +COPY /src/client /code/client COPY /src/taccsite_custom /code/taccsite_custom COPY /src/taccsite_cms /code/taccsite_cms + +# install node 20.x +RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - +RUN apt-get install -y nodejs + +RUN chmod u+x /code/client/build_client.sh && /code/client/build_client.sh +RUN cp -R /code/client/dist/static/assets/. /code/taccsite_custom/apcd_cms/static/assets/ +RUN cp -R /code/client/dist/react-assets.html /code/taccsite_custom/apcd_cms/templates/react-asset.html diff --git a/apcd_cms/README.md b/apcd_cms/README.md index f3f3b886..e949bb18 100644 --- a/apcd_cms/README.md +++ b/apcd_cms/README.md @@ -7,3 +7,56 @@ An extension of the [Core CMS](https://github.com/TACC/Core-CMS) project ## Basics See [Core-CMS-Custom](../README.md). + + +## Build + +1. cd to acpd-cms +2. run make build +3. run make start +4. cd to apcd_cms/src/client +5. run npm ci +6. run npm run build +7. run npm run dev +8. Make code changes and observe changes live in browser. + + +## Converting existing page to react based page + +### Backend + +1. Update urls.py + + Make the default page return as TemplateView.as_view(template_name=' + diff --git a/apcd_cms/src/apps/admin_exception/templates/list_admin_exception.html b/apcd_cms/src/apps/admin_exception/templates/list_admin_exception.html index f6c9dfa7..d8c31776 100644 --- a/apcd_cms/src/apps/admin_exception/templates/list_admin_exception.html +++ b/apcd_cms/src/apps/admin_exception/templates/list_admin_exception.html @@ -1,8 +1,9 @@ -{% extends "standard.html" %} +{% extends "apcd_cms/templates/standard.html" %} {% load static %} {% block content %} +
{% include "nav_cms_breadcrumbs.html" %} @@ -11,104 +12,10 @@

View Exception Requests


All submitted exception requests


-
-
- Filter by Status: - - Filter by Organization: - - {% if selected_status != 'All' or selected_org != 'All' %} - - {% endif %} -
-
- - - - {% for k in header %} - - {% endfor %} - - - - {% for r in page %} - - - - - - - - - - - {% endfor %} - -
{{k}}
{{r.created_at}}{{r.entity_name}}{{r.requestor_name}}{{r.request_type}}{{r.outcome}}{{r.status}}
- {% include 'paginator.html' %} +
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/apcd_cms/src/apps/admin_extension/urls.py b/apcd_cms/src/apps/admin_extension/urls.py index eb002d66..6f1d4e55 100644 --- a/apcd_cms/src/apps/admin_extension/urls.py +++ b/apcd_cms/src/apps/admin_extension/urls.py @@ -1,11 +1,11 @@ from django.urls import path -from apps.admin_extension.views import AdminExtensionsTable +from django.views.generic import TemplateView +from apps.admin_extension.views import AdminExtensionsTable, UpdateExtensionsView app_name = 'admin_extension' urlpatterns = [ - path('list-extensions/', AdminExtensionsTable.as_view(), name="list_extensions"), - path('list-extensions/', AdminExtensionsTable.as_view(), name='status'), - path('list-extensions/', AdminExtensionsTable.as_view(), name='org'), - path('list-extensions/', AdminExtensionsTable.as_view(), name='status_org') -] \ No newline at end of file + path('list-extensions/', TemplateView.as_view(template_name='list_admin_extension.html'), name="list_extensions"), + path('list-extensions/api/', AdminExtensionsTable.as_view(), name='admin_extensions_table_api'), + path('update-extension//', UpdateExtensionsView.as_view(), name='update_extension'), +] diff --git a/apcd_cms/src/apps/admin_extension/views.py b/apcd_cms/src/apps/admin_extension/views.py index 77aad967..8e92a9c4 100644 --- a/apcd_cms/src/apps/admin_extension/views.py +++ b/apcd_cms/src/apps/admin_extension/views.py @@ -1,90 +1,45 @@ -from django.http import HttpResponseRedirect, HttpResponse, JsonResponse -from django.core.paginator import Paginator, EmptyPage +from django.http import HttpResponseRedirect, JsonResponse from django.views.generic.base import TemplateView -from django.template import loader -from apps.utils.apcd_database import get_all_extensions, update_extension +from django.views import View +from apps.utils.apcd_database import get_all_extensions, update_extension from apps.utils.apcd_groups import is_apcd_admin from apps.utils.utils import table_filter from apps.utils.utils import title_case from apps.components.paginator.paginator import paginator -from dateutil import parser +from datetime import date as datetimeDate from datetime import datetime import logging +import json logger = logging.getLogger(__name__) + class AdminExtensionsTable(TemplateView): template_name = 'list_admin_extension.html' - def post(self, request): - - form = request.POST.copy() - - def _err_msg(resp): - if hasattr(resp, 'pgerror'): - return resp.pgerror - if isinstance(resp, Exception): - return str(resp) - return None - - def _edit_extension(form): - errors = [] - extension_response = update_extension(form) - if _err_msg(extension_response): - errors.append(_err_msg(extension_response)) - if len(errors) != 0: - logger.debug(print(errors)) - template = loader.get_template('edit_extension_error.html') - else: - logger.debug(print("success")) - template = loader.get_template('edit_extension_success.html') - return template - - template = _edit_extension(form) - return HttpResponse(template.render({}, request)) + def get(self, request, *args, **kwargs): extension_content = get_all_extensions() - - - context = self.get_context_data(extension_content, *args,**kwargs) - template = loader.get_template(self.template_name) - return HttpResponse(template.render(context, request)) + context = self.get_extensions_list_json(extension_content, *args, **kwargs) + return JsonResponse({'response': context}) def dispatch(self, request, *args, **kwargs): - if not request.user.is_authenticated or not is_apcd_admin(request.user): + if not request.user.is_authenticated or not is_apcd_admin(request.user): return HttpResponseRedirect('/') return super(AdminExtensionsTable, self).dispatch(request, *args, **kwargs) - def get_context_data(self, extension_content, *args, **kwargs): - context = super(AdminExtensionsTable, self).get_context_data(*args, **kwargs) - def _set_extensions(extension): - return { - 'extension_id': extension[0], - 'submitter_id': extension[1], - 'current_expected_date': extension[2], - 'requested_target_date': extension[3], - 'approved_expiration_date': extension[4], - # to separate small carrier into two words - 'extension_type': title_case(extension[5].replace('_', ' ')) if extension[5] else None, - 'applicable_data_period': _get_applicable_data_period(extension[6]), - 'status': title_case(extension[7]) if extension[7] else 'None', - 'outcome': title_case(extension[8]) if extension[8] else None, - 'created_at': extension[9], - 'updated_at': extension[10], - 'submitter_code': extension[11], - 'payor_code': extension[12], - 'user_id': extension[13], - 'requestor_name': title_case(extension[14]) if extension[14] else None, - 'requestor_email': extension[15], - 'explanation_justification': extension[16], - 'notes': extension[17], - 'entity_name': extension[18] - } + def get_extensions_list_json(self, extensions, *args, **kwargs): + context = {} + context['header'] = ['Created', 'Entity Organization', 'Requestor Name', 'Extension Type', 'Outcome', 'Status', 'Approved Expiration', 'Actions'] context['status_options'] = ['All'] context['org_options'] = ['All'] context['outcome_options'] = [] context['extensions'] = [] + context['action_options'] = ['Select Action', 'View Record', 'Edit Record'] + context['status_edit_options'] = [{'key': 'complete', 'value': 'Complete'}, {'key': 'pending', 'value': 'Pending'}, {'key': 'none', 'value': 'None'}] + context['outcome_edit_options'] = [{'key': 'denied', 'value': 'Denied'}, {'key': 'granted', 'value':'Granted'}, {'key': 'none', 'value': 'None'}, {'key': 'withdrawn', 'value': 'Withdrawn'}] + try: page_num = int(self.request.GET.get('page')) @@ -92,57 +47,123 @@ def _set_extensions(extension): page_num = 1 def getDate(row): - date = row[9] - return date if date is not None else parser.parse('1-1-0001') + date = row[2] + return date if date is not None else datetimeDate(1,1,1) # put 'None' date entries all together at end of listing w/ date 1-1-0001 + + extensions = sorted(extensions, key=lambda row:getDate(row), reverse=True) - extension_content = sorted(extension_content, key=lambda row:getDate(row), reverse=True) # sort extensions by newest to oldest + extensions_table_entries = [] + + for extension in extensions: + extensions_table_entries.append(self._set_extension(extension)) + context['extensions'].append(self._set_extension(extension)) - extension_table_entries = [] - for extension in extension_content: - # to be used by paginator - extension_table_entries.append(_set_extensions(extension)) - # to be able to access any extension in a template - context['extensions'].append(_set_extensions(extension)) entity_name = title_case(extension[18]) - status = title_case(extension[7]) if extension[7] else 'None' + status = title_case(extension[7]) if extension[7] else "None" outcome = title_case(extension[8]) if entity_name not in context['org_options']: context['org_options'].append(entity_name) - context['org_options'] = sorted(context['org_options'], key=lambda x: (x != 'All', x is None, x if x is not None else '')) + context['org_options'] = sorted(context['org_options'], key=lambda x: (x != 'All', x)) # Remove empty strings context['org_options'] = [option for option in context['org_options'] if option != ''] if status not in context['status_options']: context['status_options'].append(status) - context['status_options'] = sorted(context['status_options'], key=lambda x: (x != 'All', x is None, x if x is not None else '')) + context['status_options'] = sorted(context['status_options'], key=lambda x: (x != 'All', x)) if outcome not in context['outcome_options']: context['outcome_options'].append(outcome) - context['outcome_options'] = sorted(context['outcome_options'], key=lambda x: (x != 'All', x is None, x if x is not None else '')) + context['outcome_options'] = sorted(context['outcome_options'], key=lambda x: (x is not None, x)) queryStr = '' status_filter = self.request.GET.get('status') org_filter = self.request.GET.get('org') - context['selected_status'] = 'All' + context['selected_status'] = '' if status_filter is not None and status_filter != 'All': context['selected_status'] = status_filter queryStr += f'&status={status_filter}' - extension_table_entries = table_filter(status_filter, extension_table_entries, 'status') + extensions_table_entries = table_filter(status_filter, extensions_table_entries, 'ext_status') - context['selected_org'] = 'All' + context['selected_org'] = '' if org_filter is not None and org_filter != 'All': context['selected_org'] = org_filter queryStr += f'&org={org_filter}' - extension_table_entries = table_filter(org_filter.replace("(", "").replace(")",""), extension_table_entries, 'entity_name') + extensions_table_entries = table_filter(org_filter.replace("(", "").replace(")",""), extensions_table_entries, 'org_name') context['query_str'] = queryStr - context.update(paginator(self.request, extension_table_entries)) - context['pagination_url_namespaces'] = 'admin_extension:list_extensions' - + page_info = paginator(self.request, extensions_table_entries) + context['page'] = [{'org_name': obj['org_name'], 'created': obj['created'], 'type': obj['type'], 'requestor': obj['requestor'], + 'ext_outcome': obj['ext_outcome'], 'ext_status': obj['ext_status'], 'ext_id': obj['ext_id'], 'submitter_id': obj['submitter_id'], + 'approved_expiration_date': obj['approved_expiration_date'], 'current_expected_date': obj['current_expected_date'], + 'requested_target_date': obj['requested_target_date'], 'applicable_data_period': obj['applicable_data_period'], + 'updated_at': obj['updated_at'], 'submitter_code': obj['submitter_code'], 'payor_code': obj['payor_code'], 'requestor_email': obj['requestor_email'], + 'explanation_justification': obj['explanation_justification'], 'notes': obj['notes']} for obj in page_info['page']] + + context['page_num'] = page_num + context['total_pages'] = page_info['page'].paginator.num_pages + context['pagination_url_namespaces'] = 'administration:admin_extension' return context + def _set_extension(self, ext): + return { + 'org_name': ext[18] if ext[18] else "None", + 'created': ext[9] if ext[9] else "None", + 'type': title_case(ext[5].replace('_', ' ')) if ext[5] else "None", + 'requestor': title_case(ext[14]) if ext[14] else "None", + 'ext_outcome': title_case(ext[8]) if ext[8] else "None", + 'ext_status': title_case(ext[7]) if ext[7] else "None", + 'ext_id': ext[0], + 'submitter_id': ext[1], + 'approved_expiration_date': ext[4] if ext[4] else "None", + 'current_expected_date': ext[2] if ext[2] else "None", + 'requested_target_date': ext[3] if ext[3] else "None", + 'applicable_data_period': _get_applicable_data_period(ext[6]) if ext[6] else "None", + 'updated_at': ext[10] if ext[10] else "None", + 'submitter_code': ext[11] if ext[11] else "None", + 'payor_code': ext[12] if ext[12] else "None", + 'requestor_email': ext[15] if ext[15] else "None", + 'explanation_justification': ext[16] if ext[16] else "None", + 'notes': ext[17] if ext[17] else "None", + } + + # function converts int value in the format YYYYMM to a string with abbreviated month and year def _get_applicable_data_period(value): try: return datetime.strptime(str(value), '%Y%m').strftime('%b. %Y') except: return None + + +class UpdateExtensionsView(View): + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not is_apcd_admin(request.user): + return HttpResponseRedirect('/') + return super(UpdateExtensionsView, self).dispatch(request, *args, **kwargs) + + def _err_msg(self, resp): + if hasattr(resp, 'pgerror'): + return resp.pgerror + if isinstance(resp, Exception): + return str(resp) + return None + + def put(self, request, ext_id): + data = json.loads(request.body) + + updated_data = {} + updated_data['extension_id'] = ext_id + updated_data['status'] = data['ext_status'] + updated_data['outcome'] = data['ext_outcome'] + updated_data['approved_expiration_date'] = data['approved_expiration_date'] + updated_data['applicable_data_period'] = data['applicable_data_period'] + updated_data['notes'] = data['notes'] + + errors = [] + extension_response = update_extension(updated_data) + if self._err_msg(extension_response): + errors.append(self._err_msg(extension_response)) + if len(errors) != 0: + logger.error(errors) + return JsonResponse({'message': 'Cannot edit extension'}, status=500) + + return JsonResponse({'response': 'success'}) \ No newline at end of file diff --git a/apcd_cms/src/apps/admin_regis_table/static/admin_regis_table/css/table.css b/apcd_cms/src/apps/admin_regis_table/static/admin_regis_table/css/table.css index 133b2369..2435c341 100644 --- a/apcd_cms/src/apps/admin_regis_table/static/admin_regis_table/css/table.css +++ b/apcd_cms/src/apps/admin_regis_table/static/admin_regis_table/css/table.css @@ -1,5 +1,6 @@ .status-filter.org-filter { width: max-content; + padding-right: 20px; } /* SEE: https://css-tricks.com/responsive-data-tables/ */ diff --git a/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_error.html b/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_error.html deleted file mode 100644 index 086f44f3..00000000 --- a/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_error.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "standard.html" %} -{% block content %} - -{# TUP-175: Move to Core, Remove from Here #} -{% include 'snippets/tup-175-css-alerts-messages-ui-pattern.html' %} - -
- {% include "nav_cms_breadcrumbs.html" %} - -

Create Submitter

-
-

- An error occurred during submission. For help, submit a ticket. -

- Back to List Registrations -
- -{% endblock %} diff --git a/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_modal.html b/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_modal.html deleted file mode 100644 index b6c0be35..00000000 --- a/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_modal.html +++ /dev/null @@ -1,76 +0,0 @@ - diff --git a/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_success.html b/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_success.html deleted file mode 100644 index 02ddfb0a..00000000 --- a/apcd_cms/src/apps/admin_regis_table/templates/create_submitter_success.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "standard.html" %} -{% block content %} -
- {% include "nav_cms_breadcrumbs.html" %} - -

Create Submitter

-
-

- Creation of this submitter was successful. -

- Back to List Registrations -
-{% endblock %} diff --git a/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_error.html b/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_error.html deleted file mode 100644 index a1ca78d4..00000000 --- a/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_error.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "standard.html" %} -{% block content %} - -{% include 'snippets/tup-175-css-alerts-messages-ui-pattern.html' %} - -
- {% include "nav_cms_breadcrumbs.html" %} - -

Edit Registration

-
-

- An error occurred while updating this registration. For help, submit a ticket. -

- Back to List Registrations -
-{% endblock %} diff --git a/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_modal.html b/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_modal.html deleted file mode 100644 index 743efe82..00000000 --- a/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_modal.html +++ /dev/null @@ -1,26 +0,0 @@ -{% load static %} - - - - - -{% include "submission_form/registration_form_scripts.html" %} diff --git a/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_success.html b/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_success.html deleted file mode 100644 index 803596bb..00000000 --- a/apcd_cms/src/apps/admin_regis_table/templates/edit_registration_success.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "standard.html" %} -{% block content %} -
- {% include "nav_cms_breadcrumbs.html" %} - -

Edit Registration

-
-

- Updating this registration was successful. -

- Back to List Registrations -
-{% endblock %} diff --git a/apcd_cms/src/apps/admin_regis_table/templates/list_registrations.html b/apcd_cms/src/apps/admin_regis_table/templates/list_registrations.html index 7eb08dca..d6318e26 100644 --- a/apcd_cms/src/apps/admin_regis_table/templates/list_registrations.html +++ b/apcd_cms/src/apps/admin_regis_table/templates/list_registrations.html @@ -1,8 +1,7 @@ -{% extends "standard.html" %} -{% load static %} +{% extends "apcd_cms/templates/standard.html" %} +{% load static %} {% block content %} - @@ -14,107 +13,6 @@

List Registrations


All completed registration requests to become a data submitter.


-
-
- Filter by Status: - - Filter by Organization: - - {% if selected_status != 'All' or selected_org != 'All' %} - - {% endif %} -
-
- - - - {% for k in header %} - - {% endfor %} - - - - {% for r in page %} - - - - - - - - - {% endfor %} - -
{{k}}
{{r.biz_name}}{{r.year}}{{r.type}}{{r.location}}{{r.reg_status}} - {% include "view_registration_modal.html" %} - {% include "edit_registration_modal.html" %} - -
- {% include 'paginator.html' %} +
- - {% endblock %} diff --git a/apcd_cms/src/apps/admin_regis_table/templates/view_registration_modal.html b/apcd_cms/src/apps/admin_regis_table/templates/view_registration_modal.html deleted file mode 100644 index cfbbc04c..00000000 --- a/apcd_cms/src/apps/admin_regis_table/templates/view_registration_modal.html +++ /dev/null @@ -1,117 +0,0 @@ - diff --git a/apcd_cms/src/apps/admin_regis_table/urls.py b/apcd_cms/src/apps/admin_regis_table/urls.py index cb42e9ba..90e93da8 100644 --- a/apcd_cms/src/apps/admin_regis_table/urls.py +++ b/apcd_cms/src/apps/admin_regis_table/urls.py @@ -1,10 +1,10 @@ from django.urls import path +from django.views.generic import TemplateView from apps.admin_regis_table.views import RegistrationsTable app_name = 'admin_regis_table' urlpatterns = [ - path('list-registration-requests/', RegistrationsTable.as_view(), name='admin_regis_table'), - path(r'list-registration-requests/?status=(?P)/', RegistrationsTable.as_view(), name='admin_regis_table'), - path(r'list-registration-requests/?org=(?P)/', RegistrationsTable.as_view(), name='admin_regis_table'), - path(r'list-registration-requests/?status=(?P)&org=(?P)/', RegistrationsTable.as_view(), name='admin_regis_table') + path('list-registration-requests/', TemplateView.as_view(template_name='list_registrations.html'), name='admin_regis_table'), + path('list-registration-requests/api/', RegistrationsTable.as_view(), name='admin_regis_table_api'), + path('request-to-submit/api//', RegistrationsTable.as_view(), name='admin_regis_update_api'), ] diff --git a/apcd_cms/src/apps/admin_regis_table/views.py b/apcd_cms/src/apps/admin_regis_table/views.py index 5f90323d..820d4236 100644 --- a/apcd_cms/src/apps/admin_regis_table/views.py +++ b/apcd_cms/src/apps/admin_regis_table/views.py @@ -1,13 +1,26 @@ -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.views.generic.base import TemplateView from django.template import loader -from apps.utils.apcd_database import get_registrations, get_registration_contacts, get_registration_entities, update_registration, update_registration_contact, update_registration_entity +from apps.utils.apcd_database import ( + delete_registration_entity, + delete_registration_contact, + get_registrations, + get_registration_contacts, + get_registration_entities, + update_registration, + update_registration_contact, + update_registration_entity, +) from apps.utils.apcd_groups import is_apcd_admin from apps.utils.utils import table_filter -from apps.utils.registrations_data_formatting import _set_registration +from apps.utils.registrations_data_formatting import ( + _set_registration, + _set_registration_for_listing, +) from apps.components.paginator.paginator import paginator import logging from datetime import date as datetimeDate +import json logger = logging.getLogger(__name__) @@ -15,14 +28,27 @@ class RegistrationsTable(TemplateView): template_name = 'list_registrations.html' - def post(self, request): - - form = request.POST.copy() - reg_id = int(form['reg_id']) - - reg_data = get_registrations(reg_id)[0] - reg_entities = get_registration_entities(reg_id) - reg_contacts = get_registration_contacts(reg_id) + def _get_first_registration_entry(self, reg_id): + registrations = get_registrations(reg_id=reg_id) + if len(registrations) > 0: + return registrations[0] + else: + raise Exception(f'Registration not found {reg_id}') + + def post(self, request, reg_id): + form = json.loads(request.body) + reg_entities = form['entities'] + reg_contacts = form['contacts'] + + # Find the associated contacts and entities that were deleted. + updated_entity_ids = {reg['entity_id'] for reg in reg_entities if 'entity_id' in reg and reg['entity_id'] >= 0} + updated_contact_ids = {con['contact_id'] for con in reg_contacts if 'contact_id' in con and con['contact_id'] >= 0} + # Retrieve existing IDs + existing_entity_ids = {reg[3] for reg in get_registration_entities(reg_id)} + existing_contact_ids = {contact[0] for contact in get_registration_contacts(reg_id)} + # Find the deleted ones. + entity_ids_to_delete = existing_entity_ids - updated_entity_ids + contact_ids_to_delete = existing_contact_ids - updated_contact_ids def _err_msg(resp): if hasattr(resp, 'pgerror'): @@ -30,50 +56,70 @@ def _err_msg(resp): if isinstance(resp, Exception): return str(resp) return None - - def _edit_registration(form, reg_entities=reg_entities, reg_contacts=reg_contacts): - errors = [] - reg_resp = update_registration(form, reg_id) - if not _err_msg(reg_resp) and type(reg_resp) == int: - for iteration in range(1, 6): - contact_resp = update_registration_contact(form, reg_id, iteration, len(reg_contacts)) - entity_resp = update_registration_entity(form, reg_id, iteration, len(reg_entities)) - if _err_msg(contact_resp): - errors.append(_err_msg(contact_resp)) - if _err_msg(entity_resp): - errors.append(_err_msg(entity_resp)) - if len(errors) != 0: - template = loader.get_template('edit_registration_error.html') - template = loader.get_template('edit_registration_success.html') - else: - errors.append(_err_msg(reg_resp)) - template = loader.get_template('edit_registration_error.html') - return template - if 'edit-registration-form' in form: - template = _edit_registration(form) - return HttpResponse(template.render({}, request)) + reg_resp = update_registration(form, reg_id) + errors = [] + if not _err_msg(reg_resp): + for id in entity_ids_to_delete: + delete_resp = delete_registration_entity(reg_id, id) + if _err_msg(delete_resp): + errors.append(str(delete_resp)) + + for id in contact_ids_to_delete: + delete_resp = delete_registration_contact(reg_id, id) + if _err_msg(delete_resp): + errors.append(str(delete_resp)) + + for entity in reg_entities: + entity_resp = update_registration_entity(entity, reg_resp) + if _err_msg(entity_resp): + errors.append(str(entity_resp)) + for contact in reg_contacts: + contact_resp = update_registration_contact(contact, reg_resp) + if _err_msg(contact_resp): + errors.append(str(contact_resp)) + else: + errors.append(str(reg_resp)) + + if len(errors): + description = "Error(s):\n" + for err_msg in errors: + description += "{}\n".format(err_msg) + response = JsonResponse({'status': 'error', 'errors': description}, status=400) + else: + response = JsonResponse({'status': 'success', 'reg_id': reg_id}, status=200) + + return response def get(self, request, *args, **kwargs): - registrations_content = get_registrations() - registrations_entities = get_registration_entities() - registrations_contacts = get_registration_contacts() - - context = self.get_context_data(registrations_content, registrations_entities, registrations_contacts, *args,**kwargs) - template = loader.get_template(self.template_name) - return HttpResponse(template.render(context, request)) + try: + if request.GET.get('reg_id'): + reg_id = int(request.GET.get('reg_id')) + registration = self._get_first_registration_entry(reg_id) + registrations_entities = get_registration_entities(reg_id=reg_id) + registrations_contacts = get_registration_contacts(reg_id=reg_id) + return JsonResponse({'response': _set_registration(registration, registrations_entities, registrations_contacts)}) + else: + registrations_content = get_registrations() + context = self.get_registration_list_json(registrations_content, *args, **kwargs) + return JsonResponse({'response': context}) + except Exception as e: + logger.error("An error occurred: %s", str(e)) + return JsonResponse({ + 'status': 'error', + 'message': 'Internal server error', + }, status=500) def dispatch(self, request, *args, **kwargs): if not request.user.is_authenticated or not is_apcd_admin(request.user): return HttpResponseRedirect('/') return super(RegistrationsTable, self).dispatch(request, *args, **kwargs) - def get_context_data(self, registrations_content, registrations_entities, registrations_contacts, *args, **kwargs): - context = super(RegistrationsTable, self).get_context_data(*args, **kwargs) + def get_registration_list_json(self, registrations_content, *args, **kwargs): + context = {} context['header'] = ['Business Name', 'Year', 'Type', 'Location', 'Registration Status', 'Actions'] context['status_options'] = ['All', 'Received', 'Processing', 'Complete', 'Withdrawn'] - context['status_options'] = sorted(context['status_options'], key=lambda x: (x != 'All', x is None, x if x is not None else '')) context['org_options'] = ['All'] try: @@ -83,37 +129,47 @@ def get_context_data(self, registrations_content, registrations_entities, regist def getDate(row): date = row[1] - return date if date is not None else datetimeDate(1,1,1) # put 'None' date entries all together at end of listing w/ date 1-1-0001 + return date if date is not None else datetimeDate(1, 1, 1) # put 'None' date entries all together at end of listing w/ date 1-1-0001 registrations_content = sorted(registrations_content, key=lambda row:getDate(row), reverse=True) # sort registrations by newest to oldest registration_table_entries = [] for registration in registrations_content: - associated_entities = [ent for ent in registrations_entities if ent[1] == registration[0]] - associated_contacts = [cont for cont in registrations_contacts if cont[1] == registration[0]] - registration_table_entries.append(_set_registration(registration, associated_entities, associated_contacts)) + registration_table_entries.append(_set_registration_for_listing(registration)) org_name = registration[5] if org_name not in context['org_options']: context['org_options'].append(org_name) - context['org_options'] = sorted(context['org_options'],key=lambda x: (x != 'All', x is None, x if x is not None else '')) queryStr = '' status_filter = self.request.GET.get('status') org_filter = self.request.GET.get('org') - context['selected_status'] = 'All' - if status_filter and status_filter != 'All': + context['selected_status'] = None + if status_filter is not None and status_filter != 'All': context['selected_status'] = status_filter queryStr += f'&status={status_filter}' registration_table_entries = table_filter(status_filter, registration_table_entries, 'reg_status') - context['selected_org'] = 'All' - if org_filter and org_filter != 'All': + context['selected_org'] = None + if org_filter is not None and org_filter != 'All': context['selected_org'] = org_filter queryStr += f'&org={org_filter}' - registration_table_entries = table_filter(org_filter.replace("(", "").replace(")",""), registration_table_entries, 'biz_name') + registration_table_entries = table_filter(org_filter.replace("(", "").replace(")", ""), registration_table_entries, 'biz_name') context['query_str'] = queryStr - context.update(paginator(self.request, registration_table_entries)) - context['pagination_url_namespaces'] = 'admin_regis_table:admin_regis_table' + page_info = paginator(self.request, registration_table_entries) + context['page'] = [ + { + 'biz_name': obj['biz_name'], + 'year': obj['year'], + 'type': obj['type'], + 'location': obj['location'], + 'reg_status': obj['reg_status'], + 'reg_id': obj['reg_id'], + } + for obj in page_info['page'] + ] + context['page_num'] = page_num + context['total_pages'] = page_info['page'].paginator.num_pages + context['pagination_url_namespaces'] = 'administration:admin_regis_table' return context diff --git a/apcd_cms/src/apps/admin_submissions/static/admin_submissions/css/admin_table.css b/apcd_cms/src/apps/admin_submissions/static/admin_submissions/css/admin_table.css deleted file mode 100644 index d44a4c3e..00000000 --- a/apcd_cms/src/apps/admin_submissions/static/admin_submissions/css/admin_table.css +++ /dev/null @@ -1,21 +0,0 @@ -.pagination { - display: flex; - justify-content: center; - padding-top: 20px; - } - -.pagination a { - color: black; - float: left; - padding: 8px 16px; - text-decoration: none; - border: 1px solid var(--global-color-primary--light); -} - -.pagination a.active { - background-color: var(--global-color-accent--normal); - color: white; - } - -.pagination a:hover:not(.active) {background-color: var(--global-color-primary--light);} - diff --git a/apcd_cms/src/apps/admin_submissions/templates/list_admin_submissions.html b/apcd_cms/src/apps/admin_submissions/templates/list_admin_submissions.html index ccd1eb6c..eea7a919 100644 --- a/apcd_cms/src/apps/admin_submissions/templates/list_admin_submissions.html +++ b/apcd_cms/src/apps/admin_submissions/templates/list_admin_submissions.html @@ -1,4 +1,4 @@ -{% extends "standard.html" %} +{% extends "apcd_cms/templates/standard.html" %} {% load static %} {% block content %} @@ -7,103 +7,8 @@ - - -
{% include "nav_cms_breadcrumbs.html" %} - -

View Submissions

-
-

All completed submissions by organizations

-
-
-
- Filter by Status: - - Sort by: - - {% if selected_status != 'All' or selected_sort != None %} - - {% endif %} -
-
- - - - - {% for k in header %} - - {% endfor %} - - - - {% for r in page %} - - - - - - - - - - {% endfor %} - -
{{k}}
{{r.received_timestamp}}{{r.entity_name}}{{r.file_name}}{{r.outcome}}{{r.status}}{{r.updated_at}} - {% include "view_admin_submission_logs_modal.html" %} - View Logs -
- - {% include 'paginator.html' %} +
- {% endblock %} diff --git a/apcd_cms/src/apps/admin_submissions/urls.py b/apcd_cms/src/apps/admin_submissions/urls.py index abf229e0..c03d9920 100644 --- a/apcd_cms/src/apps/admin_submissions/urls.py +++ b/apcd_cms/src/apps/admin_submissions/urls.py @@ -1,10 +1,12 @@ from django.urls import path +from django.views.generic import TemplateView from apps.admin_submissions.views import AdminSubmissionsTable app_name = 'administration' urlpatterns = [ - path('list-submissions/', AdminSubmissionsTable.as_view(), name="admin_submissions"), - path(r'list-submissions/?status=(?P)/', AdminSubmissionsTable.as_view(), name="admin_submissions"), - path(r'list-submissions/?sort=(?P)/', AdminSubmissionsTable.as_view(), name="admin_submissions"), - path(r'list-submissions/?sort=(?P)&filter=(?P)/', AdminSubmissionsTable.as_view(), name="admin_submissions"), + path('list-submissions/', TemplateView.as_view(template_name='list_admin_submissions.html'), name="admin_submissions"), + path('list-submissions/api/', AdminSubmissionsTable.as_view(), name="admin_submissions_api"), + path('list-submissions/api/options', AdminSubmissionsTable.as_view(), name='admin_submissions_api_options'), + path('view_log', AdminSubmissionsTable.as_view(), name='admin-submissions-view-log'), + ] diff --git a/apcd_cms/src/apps/admin_submissions/views.py b/apcd_cms/src/apps/admin_submissions/views.py index abf61087..907da1f6 100644 --- a/apcd_cms/src/apps/admin_submissions/views.py +++ b/apcd_cms/src/apps/admin_submissions/views.py @@ -1,9 +1,9 @@ -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, JsonResponse, Http404, HttpResponse +from django.core.paginator import Paginator from django.views.generic.base import TemplateView -from apps.utils.apcd_database import get_all_submissions_and_logs +from apps.utils.apcd_database import get_all_submissions_and_logs, get_user_submission_log from apps.utils.apcd_groups import is_apcd_admin -from apps.utils.utils import title_case, table_filter -from apps.components.paginator.paginator import paginator +from apps.utils.utils import title_case import logging from dateutil import parser @@ -12,70 +12,133 @@ class AdminSubmissionsTable(TemplateView): template_name = 'list_admin_submissions.html' - def dispatch(self, request, *args, **kwargs): if not request.user.is_authenticated or not is_apcd_admin(request.user): return HttpResponseRedirect('/') return super(AdminSubmissionsTable, self).dispatch(request, *args, **kwargs) + + def get(self, request, *args, **kwargs): + if 'options' in request.path: + return self.get_options(request) + if 'view_log' in request.path: + return SubmissionsLogView.get_log(request, is_admin=True) + + status = request.GET.get('status', 'In Process') + sort = request.GET.get('sort', 'Newest Received') + page_number = int(request.GET.get('page', 1)) + items_per_page = int(request.GET.get('limit', 50)) + try: + submission_content = get_all_submissions_and_logs() + filtered_submissions = self.filtered_submissions(submission_content, status, sort) + + paginator = Paginator(filtered_submissions, items_per_page) + page_info = paginator.get_page(page_number) + + context = self.get_view_submissions_json(list(page_info), selected_status=status, selected_sort=sort) + context['page_num'] = page_info.number + context['total_pages'] = paginator.num_pages + return JsonResponse({'response': context}) + except Exception as e: + logger.error("Error fetching filtered user data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context.update(self.get_view_submissions_json(get_all_submissions_and_logs())) + return context - def get_context_data(self, *args, **kwargs): - - context = super(AdminSubmissionsTable, self).get_context_data(*args, **kwargs) - - submission_content = get_all_submissions_and_logs() - - context['status_options'] = ['All'] - for i in submission_content: - status = title_case(i['status']) if i['status'] else 'None' - if status not in context['status_options']: - context['status_options'].append(status) - context['status_options'] = sorted(context['status_options'], key=lambda x: (x != 'All', x is None, x if x is not None else '')) - - - queryStr = '' - dateSort = self.request.GET.get('sort') - status_filter = self.request.GET.get('status') - - def getDate(row): - date = row['received_timestamp'] - return parser.parse(date) if date is not None else parser.parse('1-1-3005') # put 'None' date entries all together at top/bottom depending on direction of sort - - if dateSort is not None: - context['selected_sort'] = dateSort - queryStr += f'&sort={dateSort}' - submission_content = sorted(submission_content, key=lambda row:getDate(row), reverse=(dateSort == 'newDate')) - + def get_options(self, request): try: - page_num = int(self.request.GET.get('page')) - except: - page_num = 1 - - context['selected_status'] = 'All' - if status_filter is not None and status_filter != 'All': - context['selected_status'] = status_filter - queryStr += f'&status={status_filter}' - submission_content = table_filter(status_filter, submission_content, 'status') - - limit = 50 - offset = limit * (page_num - 1) - - # modifies the object fields for display, only modifies a subset of entries that will be displayed - # on the current page using offset and limit - for s in submission_content[offset:offset + limit]: - s['status'] = title_case(s['status']) if s['status'] else None - s['entity_name'] = title_case(s['entity_name']) if s['entity_name'] else None - s['outcome'] = title_case(s['outcome']) if s['outcome'] else None - s['received_timestamp'] = parser.parse(s['received_timestamp']) if s['received_timestamp'] else None - s['updated_at'] = parser.parse(s['updated_at']) if s['updated_at'] else None - s['view_modal_content'] = [{ - **t, - 'outcome': title_case(t['outcome']) if t['outcome'] else None - } for t in (s['view_modal_content'] or [])] - - context['header'] = ['Received', 'Entity Organization', 'File Name', ' ', 'Outcome', 'Status', 'Last Updated', 'Actions'] - context['sort_options'] = {'newDate': 'Newest Received', 'oldDate': 'Oldest Received'} - - context['query_str'] = queryStr - context.update(paginator(self.request, submission_content, limit)) - context['pagination_url_namespaces'] = 'admin_submission:admin_submissions' + status_options = ['All', 'In Process', 'Complete'] + sort_options = [ {'name': 'Newest Received', 'value': 'newDate'}, + {'name': 'Oldest Received', 'value': 'oldDate'}] + + return JsonResponse({ + 'status_options': status_options, + 'sort_options': sort_options, + }) + except Exception as e: + logger.error("Error fetching options data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + def filtered_submissions(self, submission_content, status, sort): + def getDate(submission): + date = submission['received_timestamp'] + return parser.parse(date) if date is not None else parser.parse('1-1-3005') + + if status != 'All': + submission_content = [submission for submission in submission_content + if submission['status'].lower() == status.lower()] + + submission_content = sorted( + submission_content, + key=lambda row: getDate(row), + reverse=(sort == 'Newest Received') + ) + return submission_content + + def get_view_submissions_json(self, submission_content, selected_status='All', selected_sort='Newest Received'): + context = { + 'page': [], + 'selected_status': selected_status, + 'selected_sort': selected_sort, + 'pagination_url_namespaces':'admin_submission:admin_submissions' + } + + def _set_submissions(submission): + return { + 'submission_id': submission['submission_id'], + 'status': submission['status'], + 'entity_name': submission['entity_name'], + 'file_name': submission['file_name'], + 'outcome': title_case(submission['outcome']) if submission['outcome'] else None, + 'received_timestamp': submission['received_timestamp'], + 'updated_at': submission['updated_at'], + 'view_modal_content': submission['view_modal_content'], + } + for submission in submission_content: + context['page'].append(_set_submissions(submission)) + return context + + +class SubmissionsLogView(): + @classmethod + def get_required_param(cls, request, param_name, default=None): + value = request.GET.get(param_name, default) + if value is None: + raise Http404(f"Missing required query parameter: {param_name}") + return value + + @classmethod + def get_log(cls, request, is_admin=False): + try: + log_type = SubmissionsLogView.get_required_param(request, 'log_type', default='html') + log_id = SubmissionsLogView.get_required_param(request, 'log_id') + + user = None if is_admin else request.user.username + results = get_user_submission_log(log_id, log_type, user) + if not results: + raise Http404("Log not found or empty.") + + file_path = results[0][1] + file_name = file_path.split('/')[-1] if '/' in file_path else file_path + + content_types = { + 'html': "text/html", + 'json': "application/json", + } + + if log_type not in content_types: + raise Http404("Unsupported log type requested.") + + response = HttpResponse(str(results[0][0]), content_type=content_types[log_type]) + response['Content-Disposition'] = f'attachment; filename="{file_name}"' + return response + + except Http404 as e: + logger.warning("Log not found or unsupported log type: %s", e) + raise + except Exception as e: + logger.error("Error fetching log data: %s", e) + return JsonResponse({'error': 'Internal error fetching log.'}, status=500) \ No newline at end of file diff --git a/apcd_cms/src/apps/common_api/apps.py b/apcd_cms/src/apps/common_api/apps.py new file mode 100644 index 00000000..b428f628 --- /dev/null +++ b/apcd_cms/src/apps/common_api/apps.py @@ -0,0 +1,4 @@ +from django.apps import AppConfig + +class common_api(AppConfig): + name = 'apps.common_api' diff --git a/apcd_cms/src/apps/common_api/urls.py b/apcd_cms/src/apps/common_api/urls.py new file mode 100644 index 00000000..1ca64d93 --- /dev/null +++ b/apcd_cms/src/apps/common_api/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from apps.common_api.views import EntitiesView, cdlsView, DataPeriodsView + +app_name = 'common_api' +urlpatterns = [ + path('entities/', EntitiesView.as_view(), name='entities_api'), + path('cdls/', cdlsView.as_view(), name='cdls_api'), + path('cdls/', cdlsView.as_view(), name='cdls_api'), + path('data_periods/', DataPeriodsView.as_view(), name='dataperiods_api') +] diff --git a/apcd_cms/src/apps/common_api/views.py b/apcd_cms/src/apps/common_api/views.py new file mode 100644 index 00000000..c72bb4d8 --- /dev/null +++ b/apcd_cms/src/apps/common_api/views.py @@ -0,0 +1,107 @@ +from django.http import HttpResponseRedirect, JsonResponse, Http404 +from django.views.generic import TemplateView +from apps.utils import apcd_database +from apps.utils.apcd_groups import has_apcd_group, is_apcd_admin +from apps.utils.utils import title_case +from datetime import datetime +import logging + +logger = logging.getLogger(__name__) + + +class EntitiesView(TemplateView): + def get(self, request, *args, **kwargs): + submitters = apcd_database.get_submitter_info(request.user.username) + + submitter_info_json = self.get_submitter_info_json(submitters) + + context = {**submitter_info_json} + return JsonResponse({'response': context}) + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not has_apcd_group(request.user): + return HttpResponseRedirect('/') + return super(EntitiesView, self).dispatch(request, *args, **kwargs) + + def get_submitter_info_json(self, submitters): + context = {} + + def _set_submitter(sub, data_periods): + return { + "submitter_id": sub[0], + "submitter_code": sub[1], + "payor_code": sub[2], + "user_name": sub[3], + "entity_name": title_case(sub[4]), + "data_periods": data_periods + } + + context["submitters"] = [] + + for submitter in submitters: + data_periods = _getApplicableDataPeriods(submitter[0]) + context["submitters"].append(_set_submitter(submitter, data_periods)) + + return context + + +class cdlsView(TemplateView): + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not has_apcd_group(request.user): + return HttpResponseRedirect('/') + return super(cdlsView, self).dispatch(request, *args, **kwargs) + + def get(self, request, *args, **kwargs): + file_type = kwargs.get('file_type') + + cdls = apcd_database.get_cdl_exceptions(file_type) + + cdls_response = [] + + def _set_cdls(cdl): + return { + "field_list_code": cdl[0], + "field_list_value": cdl[1], + "threshold_value": cdl[2], + } + + for cdl in cdls: + cdls_response.append(_set_cdls(cdl)) + + return JsonResponse({"cdls": cdls_response}) + + +class DataPeriodsView(TemplateView): + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not is_apcd_admin(request.user): + return HttpResponseRedirect('/') + return super(DataPeriodsView, self).dispatch(request, *args, **kwargs) + + def get(self, request, *args, **kwargs): + submitter_id = request.GET.get('submitter_id', None) + if submitter_id is None: + raise Http404("Submitter Id not provided") + applicable_data_periods = _getApplicableDataPeriods(submitter_id) + + return JsonResponse({'response': {"data_periods": applicable_data_periods}}) + + +def _getApplicableDataPeriods(submitter_id): + def _get_applicable_data_period(value): + try: + return datetime.strptime(str(value), '%Y%m').strftime('%Y-%m') + except Exception: + return None + + data_periods = [] + applicable_data_periods = apcd_database.get_applicable_data_periods(submitter_id) + for data_period_tuple in applicable_data_periods: + for data_period in data_period_tuple: + data_period = _get_applicable_data_period(data_period) + expected_dates = apcd_database.get_current_exp_date(submitter_id=submitter_id, applicable_data_period=data_period.replace('-', '')) + data_periods.append({ + 'data_period': data_period, + 'expected_date': expected_dates[0][0] if expected_dates else '' + }) + data_periods = sorted(data_periods, key=lambda x: x['data_period'], reverse=True) + return data_periods diff --git a/apcd_cms/src/apps/exception/static/forms/css/exception_submission_form.css b/apcd_cms/src/apps/exception/static/forms/css/exception_submission_form.css deleted file mode 100644 index a93b29af..00000000 --- a/apcd_cms/src/apps/exception/static/forms/css/exception_submission_form.css +++ /dev/null @@ -1,45 +0,0 @@ -/*Text Style*/ -#justification-asterisk { - padding-left: 0; - margin-left: 0; -} - -/*To stop buttons from appearing next to required suffix*/ -input[id^="threshold-requested"]::-webkit-inner-spin-button, -input[id^="threshold-requested"]::-webkit-outer-spin-button - { - -webkit-appearance: none; - margin: 0; - -moz-appearance:textfield; -} - -[id^="required_threshold"] { - background-color: #e9ecef; - color: #6c757d; - border-color: #ced4da; - cursor: not-allowed; -} - -/* Field Sizes */ -[id^="threshold-requested"], [id^="expiration-date"], [id^="required_threshold"] { - min-width: 15ch; -} -/* To make sure sup values are not cut off when set as a label*/ -label[name^="date-row"] { - margin-top: 1rem; -} -/* Field Layouts */ - -[id^="exception_block"] { - - /* Expectations: - - automatically enough columns - - maximum column count of 3 (i.e. minimum column width of 33%) - - maximum column width of 75 char's (same as max-width of fields) - - equal width columns - */ - display: grid; - column-gap: var(--global-space--grid-gap); - grid-template-columns: repeat(auto-fill, var(--max-col-width)); - max-width: calc(var(--global-space--grid-gap) + var(--max-col-width) * 2); -} \ No newline at end of file diff --git a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_err_no_sub_id.html b/apcd_cms/src/apps/exception/templates/exception_err_no_sub_id.html similarity index 100% rename from apcd_cms/src/apps/exception/templates/exception_submission_form/exception_err_no_sub_id.html rename to apcd_cms/src/apps/exception/templates/exception_err_no_sub_id.html diff --git a/apcd_cms/src/apps/exception/templates/exception_submission_form.html b/apcd_cms/src/apps/exception/templates/exception_submission_form.html new file mode 100644 index 00000000..8e187631 --- /dev/null +++ b/apcd_cms/src/apps/exception/templates/exception_submission_form.html @@ -0,0 +1,11 @@ +{% extends "apcd_cms/templates/standard.html" %} +{% load static %} + +{% block content %} + +
+ {% include "nav_cms_breadcrumbs.html" %} +
+
+
+{% endblock %} diff --git a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_form_success.html b/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_form_success.html deleted file mode 100644 index 80cc6d21..00000000 --- a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_form_success.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "standard.html" %} -{% block content %} -
- {% include "nav_cms_breadcrumbs.html" %} - -

Request to Submit Exception

-
-

- Your exception submission was successful. -

- Go Back to Exception Form -
-{% endblock %} \ No newline at end of file diff --git a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_other_form.html b/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_other_form.html deleted file mode 100644 index 1e8201c3..00000000 --- a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_other_form.html +++ /dev/null @@ -1,181 +0,0 @@ -{% extends "standard.html" %} -{% load static %} - -{% block content %} - - - -
- {% include "nav_cms_breadcrumbs.html" %} - - - -
-
-

Other Exception Request

-
- -

- This form should be completed and submitted only by entities who are - eligible for an exception to certain data submission requirements under H.B. 2090 (87(R)) - and associated regulations. Please review the legislation and regulation before - submitting this form. Links to both can be found on the - Texas All-Payor Claims Database - website. -

- -
-
-
-

Exception Time Period

-

Provide the requested expiration date for your request.

-
- -
-
- {% csrf_token %} -
- - - - - -
-
- -
- -

Request and Justification

- -
-

Provide rationale for the exception request, outlining the reasons why the - organization is unable to comply with the relevant requirements. Provide as - much detail as possible regarding the exception request, indicating the - specific submission requirements for which relief is being sought. If applicable, - indicate how the organization plans to become compliant.**

- - - - -
- 2000 character limit -
-
- -
-

Acknowledgment of Terms

-
-
- - - - -
-
- - - - -
-
-
- -
- - - - -
- -
- - - -
- - -
- -
- - - - - {# Hidden links for future pages #} - {# TODO: Allow this template to render CMS admin-entered markup #} - - - {# Scripts #} - - - {# Footnotes #} -
-
- * Exceptions cannot be granted for periods longer than a year.
- ** Exceptions cannot be granted "from any requirement in insurance code Chapter 38".
-
-
-
-
- {% endblock %} \ No newline at end of file diff --git a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_selection_page.html b/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_selection_page.html deleted file mode 100644 index d61149f8..00000000 --- a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_selection_page.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "standard.html" %} -{% load static %} - -{% block content %} - - - -
- {% include "nav_cms_breadcrumbs.html" %} - -
-
-

Request an Exception

- {% csrf_token %} - -
-

Please choose the type of exception to submit. If your entity requires a reporting - threshold - reduction, please select the threshold option. - For all other exceptions, please select other. -

- - - {# Hidden links for future pages #} - {# TODO: Allow this template to render CMS admin-entered markup #} - - - {% endblock %} \ No newline at end of file diff --git a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_submission_error.html b/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_submission_error.html deleted file mode 100644 index e3ed127a..00000000 --- a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_submission_error.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "standard.html" %} -{% block content %} - -{# TUP-175: Move to Core, Remove from Here #} -{% include 'snippets/tup-175-css-alerts-messages-ui-pattern.html' %} - -
- {% include "nav_cms_breadcrumbs.html" %} - -

Request to Submit Exception

-
-

- An error occurred during your exception request submission. For help, submit a ticket. -

- Go Back to Exception Form -
- -{% endblock %} diff --git a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_threshold_form.html b/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_threshold_form.html deleted file mode 100644 index d26c7193..00000000 --- a/apcd_cms/src/apps/exception/templates/exception_submission_form/exception_threshold_form.html +++ /dev/null @@ -1,481 +0,0 @@ -{% extends "standard.html" %} -{% load static %} - -{% block content %} - - - -
- {% include "nav_cms_breadcrumbs.html" %} -

Threshold Exception Request

-
-

- This form should be completed and submitted only by entities who are - eligible for an exception to certain data submission requirements under H.B. 2090 (87(R)) - and associated regulations. Please review the legislation and regulation before - submitting this form. Links to both can be found on the - Texas All-Payor Claims Database - website. -

-
-
-
- {% csrf_token %} - -
-
-

Requested Threshold Reduction

-
-
-
- - - -
-
- - - - - - -
-
- - - -
-
-
- - - -
-
- - -
- - % -
- -
-
-
-
- - - -
- - % -
-
-
-
- -
- -
- -
- -
- - -
-

Request and Justification

-
-

Provide rationale for the exception request, outlining the reasons why the - organization is unable to comply with the relevant requirements. Provide as - much detail as possible regarding the exception request, indicating the - specific submission requirements for which relief is being sought. If applicable, - indicate how the organization plans to become compliant.**

- - - - -
- 2000 character limit -
-
-
-

Acknowledgment of Terms

-
-
- - - - -
-
- - - - -
-
- -
- - - -
-
- -
-
-
- - {# Scripts #} - - - - {# Footnotes #} -
-
- - * Exceptions cannot be granted for periods longer than a year.
- ** Exceptions cannot be granted "from any requirement in insurance code Chapter 38".
-
-
-
-{% endblock %} diff --git a/apcd_cms/src/apps/exception/urls.py b/apcd_cms/src/apps/exception/urls.py index 2999dc58..71dbf63f 100644 --- a/apcd_cms/src/apps/exception/urls.py +++ b/apcd_cms/src/apps/exception/urls.py @@ -1,13 +1,12 @@ from django.urls import path from apps.exception.views import ExceptionFormView from . import views -from apps.exception.views import ExceptionOtherFormView -from apps.exception.views import ExceptionThresholdFormView +from django.views.generic import TemplateView +#from apps.exception.views import ExceptionOtherFormView +#from apps.exception.views import ExceptionThresholdFormView app_name = 'exception' urlpatterns = [ - path('exception/', ExceptionFormView.as_view(), name="index"), - path('threshold-exception/', ExceptionThresholdFormView.as_view(), name="threshold-exception"), - path('get-cdls/', views.get_cdls, name='get-cdls'), - path('other-exception/', ExceptionOtherFormView.as_view(), name="other-exception") + path('exception/', TemplateView.as_view(template_name='exception_submission_form.html'), name='exception'), + path('exception/api/', ExceptionFormView.as_view(), name='exception-api'), ] diff --git a/apcd_cms/src/apps/exception/views.py b/apcd_cms/src/apps/exception/views.py index c7bdbd11..b45d5a70 100644 --- a/apcd_cms/src/apps/exception/views.py +++ b/apcd_cms/src/apps/exception/views.py @@ -10,195 +10,39 @@ logger = logging.getLogger(__name__) class ExceptionFormView(TemplateView): - template_name = "exception_submission_form/exception_selection_page.html" - - def dispatch(self, request, *args, **kwargs): - if not request.user.is_authenticated or not has_apcd_group(request.user): - return HttpResponseRedirect('/') - return super(ExceptionFormView, self).dispatch(request, *args, **kwargs) -class ExceptionThresholdFormView(TemplateView): - def get_template_names(self): - submitters = self.request.session.get("submitters") - ## If no submitter_id for user, should not show form but show error page - if all(submitter[0] is None for submitter in submitters): - return ["exception_submission_form/exception_err_no_sub_id.html"] - else: - return ["exception_submission_form/exception_threshold_form.html"] - - def dispatch(self, request, *args, **kwargs): - if not request.user.is_authenticated or not has_apcd_group(request.user): - return HttpResponseRedirect('/') - return super(ExceptionThresholdFormView, self).dispatch(request, *args, **kwargs) - - def get_context_data(self, *args, **kwargs): - context = super(ExceptionThresholdFormView, self).get_context_data(*args, **kwargs) - - user = self.request.user.username - - submitters = apcd_database.get_submitter_info(user) - - file_type = self.request.GET.get('file_type') - - context['file_type'] = file_type - - - self.request.session['submitters'] = submitters - - self.request.session['file_type'] = file_type - - def _set_submitter(sub): - return { - "submitter_id": sub[0], - "submitter_code": sub[1], - "payor_code": sub[2], - "user_name": sub[3], - "entity_name": title_case(sub[4]) - } - - def _set_cdl(file_type): - return { - "field_list_code": file_type[0], - "field_list_value": file_type[1], - "threshold_value": file_type[2] - } - - context["submitters"] = [] - - for submitter in submitters: - context["submitters"].append(_set_submitter(submitter)) - - - return context - def post(self, request): if (request.user.is_authenticated) and has_apcd_group(request.user): + form = json.loads(request.body) + exception_type = form['exceptionType'] + if exception_type == 'threshold': + exceptions = form['exceptions'] + errors = [] + submitters = apcd_database.get_submitter_info(request.user.username) + for exception in exceptions: + submitter = next(submitter for submitter in submitters if int(submitter[0] == int(exception['businessName']))) + exception_response = apcd_database.create_threshold_exception(form, exception, submitter) + if exception_response: + errors.append(exception_response) + if errors: + return JsonResponse({'status': 'error', 'errors': errors}, status=400) + return JsonResponse({'status': 'success'}, status=200) + + if exception_type == 'other': + errors = [] + submitters = apcd_database.get_submitter_info(request.user.username) + submitter = next(submitter for submitter in submitters if int(submitter[0] == int(form['otherExceptionBusinessName']))) + other_exception_response = apcd_database.create_other_exception(form, submitter) + if other_exception_response: + errors.append(other_exception_response) + if errors: + return JsonResponse({'status': 'error', 'errors': errors}, status=400) + return JsonResponse({'status': 'success'}, status=200) - form = request.POST.copy() - errors = [] - submitters = request.session.get('submitters') - - # To create counter of exception requests and corresponding fields - max_iterations = 1 - for i in range(2, 6): - if form.get('field-threshold-exception_{}'.format(i)): - max_iterations += 1 - else: - break - - for iteration in range(max_iterations): - submitter = next(submitter for submitter in submitters if int(submitter[0]) == int(form['business-name_{}'.format(iteration + 1)])) - if _err_msg(submitter): - errors.append(_err_msg(submitter)) - except_response = apcd_database.create_threshold_exception(form, iteration + 1, submitter) - if _err_msg(except_response): - errors.append(_err_msg(except_response)) - - if len(errors): - template = loader.get_template( - "exception_submission_form/exception_submission_error.html" - ) - response = HttpResponse(template.render({}, request)) - else: - template = loader.get_template( - "exception_submission_form/exception_form_success.html" - ) - response = HttpResponse(template.render({}, request)) - - return response else: return HttpResponseRedirect('/') -class ExceptionOtherFormView(TemplateView): - def get_template_names(self): - submitters = self.request.session.get("submitters") - ## If no submitter_id for user should not show form but show error page - if all(submitter[0] is None for submitter in submitters): - return ["exception_submission_form/exception_err_no_sub_id.html"] - else: - return ["exception_submission_form/exception_other_form.html"] def dispatch(self, request, *args, **kwargs): if not request.user.is_authenticated or not has_apcd_group(request.user): return HttpResponseRedirect('/') - return super(ExceptionOtherFormView, self).dispatch(request, *args, **kwargs) - - def get_context_data(self, *args, **kwargs): - context = super(ExceptionOtherFormView, self).get_context_data(*args, **kwargs) - - user = self.request.user.username - - submitters = apcd_database.get_submitter_info(user) - - self.request.session['submitters'] = submitters - - def _set_submitter(sub): - return { - "submitter_id": sub[0], - "submitter_code": sub[1], - "payor_code": sub[2], - "user_name": sub[3], - "entity_name": title_case(sub[4]) - } - - context["submitters"] = [] - - for submitter in submitters: - context["submitters"].append(_set_submitter(submitter)) - - return context - - def post(self, request): - if (request.user.is_authenticated) and has_apcd_group(request.user): - - form = request.POST.copy() - errors = [] - submitters = request.session.get('submitters') - - submitter = next(submitter for submitter in submitters if int(submitter[0]) == int(form['business-name'])) - - if _err_msg(submitter): - errors.append(_err_msg(submitter)) - - except_response = apcd_database.create_other_exception(form, submitter) - if _err_msg(except_response): - errors.append(_err_msg(except_response)) - - if len(errors): - template = loader.get_template( - "exception_submission_form/exception_submission_error.html" - ) - response = HttpResponse(template.render({}, request)) - else: - template = loader.get_template( - "exception_submission_form/exception_form_success.html" - ) - response = HttpResponse(template.render({}, request)) - - return response - else: - return HttpResponseRedirect('/') - -def get_cdls(request): - file_type = request.GET.get('file_type') - - cdls = apcd_database.get_cdl_exceptions(file_type) - - cdlsResponse = [] - - ## To make cdlsResponse into a list to pass to the script - for cdl in cdls: - cdls_dict = { - "field_list_code": cdl[0], - "field_list_value": cdl[1], - "threshold_value": cdl[2] - } - cdlsResponse.append(cdls_dict) - - return JsonResponse((cdlsResponse), safe=False) - + return super(ExceptionFormView, self).dispatch(request, *args, **kwargs) -def _err_msg(resp): - if hasattr(resp, "pgerror"): - return resp.pgerror - if isinstance(resp, Exception): - return str(resp) - return None \ No newline at end of file diff --git a/apcd_cms/src/apps/extension/static/forms/css/extension_submission_form.css b/apcd_cms/src/apps/extension/static/forms/css/extension_submission_form.css deleted file mode 100644 index 83b91f6c..00000000 --- a/apcd_cms/src/apps/extension/static/forms/css/extension_submission_form.css +++ /dev/null @@ -1,47 +0,0 @@ -/* Field Widths */ -select { - overflow: hidden; - white-space:pre; - text-overflow: ellipsis; - } - -/* to make submission date inputs the same size*/ -select[name^="applicable-data-period"] { - max-width: 20ch; -} -/* Text alignment */ -/* To make required text line up with helper text for justification text area*/ -#justification-asterisk { - padding-left: 0; - margin-left: 0; - } - - -/* Field Layouts */ -/* To put required for extension dates on another line to avoid cutting off text */ -label[name^="extension-date-asterisk"] { - padding: 0; - margin-left:0; -} -/* To make sure sup values are not cut off when set as a label*/ -label[name^="date-row"] { - margin-top: 1rem; -} -/* To make (radio/check)box sets take up less vertical space */ -#on-behalf-of { - display: flex; - flex-wrap: wrap; - column-gap: 1em; - row-gap: 0.5em; -} - -[id^="extension-block_"] { - - /* Expectations: - - automatically enough columns - - maximum column count of 3 (i.e. minimum column width of 33%) - - equal width columns*/ - display: grid; - grid-template-columns: repeat( auto-fill, var(--max-col-width)); - max-width: calc( var(--global-space--grid-gap) + var(--max-col-width) *3 ); -} diff --git a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_err_no_sub_id.html b/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_err_no_sub_id.html deleted file mode 100644 index cd4995b3..00000000 --- a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_err_no_sub_id.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "standard.html" %} -{% load static %} - -{% block content %} - - - -
- {% include "nav_cms_breadcrumbs.html" %} - -
-
-

Request an Extension

-
- -

- This form should be completed and submitted by data submitters to request - an extension to the deadline for submitting either a regular submission or - a corrected resubmission. Please review the - Data Submission Guide for details about completing and submitting this form, especially - regarding the timeliness of the request. -

-
-

- We have not found a submitter code on file for your account. For assistance, please submit a ticket. -

- Go to Dashboard -
- {% endblock %} diff --git a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_form_success.html b/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_form_success.html deleted file mode 100644 index 7394bf76..00000000 --- a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_form_success.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "standard.html" %} -{% block content %} -
- {% include "nav_cms_breadcrumbs.html" %} - -

Request to Submit Extension

-
-

- Your extension submission was successful. -

- Go to Dashboard -
-{% endblock %} diff --git a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_error.html b/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_error.html deleted file mode 100644 index 2ff06825..00000000 --- a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_error.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "standard.html" %} -{% block content %} - -{# TUP-175: Move to Core, Remove from Here #} -{% include 'snippets/tup-175-css-alerts-messages-ui-pattern.html' %} - -
- {% include "nav_cms_breadcrumbs.html" %} - -

Request to Submit Extension

-
-

- An error occurred during your extension request submission. For help, submit a ticket. -

- Go Back to Extensions -
- -{% endblock %} diff --git a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_form.html b/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_form.html index 55ff84ea..57155bdd 100644 --- a/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_form.html +++ b/apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_form.html @@ -1,447 +1,11 @@ -{% extends "standard.html" %} +{% extends "apcd_cms/templates/standard.html" %} {% load static %} {% block content %} - -
{% include "nav_cms_breadcrumbs.html" %} - - - -
-
-

Request an Extension

-
- -

- This form should be completed and submitted by data submitters to request - an extension to the deadline for submitting either a regular submission or - a corrected resubmission. Please review the - Data Submission Guide for details about completing and submitting this form, especially - regarding - the timeliness of the request. -

- -
- -
-
- {% csrf_token %} -

Extension Information

-
-
-

- This extension is on behalf of the following organization: -

- - - -
- -
- - - -
- -
Submission Dates
-
-
- - - -
- Enter month and year -
-
-
- - - - - -
-
- - - - - - -
-
-
- -
- -
- -
- -
- - - -
- -

Request and Justification

- -
- Provide rationale for the extension request, outlining the reasons why the - organization is unable to comply with the relevant requirements. Provide as - much detail as possible regarding the extension request, indicating the - specific submission requirements for which relief is being sought. If applicable, - indicate how the organization plans to become compliant. - - - - -
- 2000 character limit -
-
-
- -

Acknowledgment of Terms

-
-
- - - - -
-
- - - - -
-
- -
- - - -
- - -
- -
-
-
-
-

- ¹ Applicable data period – month/year in which claims data was adjudicated.
- ² Requested target date – requested day/month/year by which the data should be received (the extension - date).
- ³ Current expected date – day/month/year in which applicable data was expected within the submission - window. -
-

-
-
-
-
+
- - - - - - -{# Scripts #} - - - - {% endblock %} \ No newline at end of file +{% endblock %} diff --git a/apcd_cms/src/apps/extension/urls.py b/apcd_cms/src/apps/extension/urls.py index 55ff6a3c..56f0eabe 100644 --- a/apcd_cms/src/apps/extension/urls.py +++ b/apcd_cms/src/apps/extension/urls.py @@ -1,9 +1,9 @@ from django.urls import path +from django.views.generic import TemplateView from apps.extension.views import ExtensionFormView -from . import views app_name = 'extension' urlpatterns = [ - path('extension-request/', ExtensionFormView.as_view(), name='index'), - path('get-expected-date/', views.get_expected_date, name='get-expected-date'), + path('extension-request/', TemplateView.as_view(template_name='extension_submission_form/extension_submission_form.html'), name='extension'), + path('extension/api/', ExtensionFormView.as_view(), name='extension-api'), ] diff --git a/apcd_cms/src/apps/extension/views.py b/apcd_cms/src/apps/extension/views.py index b992cf35..f470cb68 100644 --- a/apcd_cms/src/apps/extension/views.py +++ b/apcd_cms/src/apps/extension/views.py @@ -1,11 +1,11 @@ -from django.http import HttpResponse, HttpResponseRedirect, JsonResponse -from django.template import loader +from django.http import JsonResponse, HttpResponseRedirect from django.views.generic.base import TemplateView from apps.utils import apcd_database from apps.utils.apcd_groups import has_apcd_group from apps.utils.utils import title_case from datetime import datetime import logging +import json logger = logging.getLogger(__name__) @@ -17,99 +17,37 @@ def dispatch(self, request, *args, **kwargs): return HttpResponseRedirect('/') return super(ExtensionFormView, self).dispatch(request, *args, **kwargs) - def get_context_data(self, *args, **kwargs): - context = super(ExtensionFormView, self).get_context_data(*args, **kwargs) - - user = self.request.user.username - - submitters = apcd_database.get_submitter_info(user) - - self.request.session['submitters'] = submitters - - def _set_submitter(sub, applicable_data_periods): - return { - "submitter_id": sub[0], - "submitter_code": sub[1], - "payor_code": sub[2], - "user_name": sub[3], - "entity_name": title_case(sub[4]), - "applicable_data_periods": applicable_data_periods - } - context["submitters"] = [] - context["applicable_data_periods"] = [] - - for submitter in submitters: - applicable_data_periods = apcd_database.get_applicable_data_periods(submitter[0]) - data_periods = [] - for data_period_tuple in applicable_data_periods: - for data_period in data_period_tuple: - data_period = _get_applicable_data_period(data_period) - data_periods.append(data_period) - data_periods = sorted(data_periods, reverse=True) - context['submitters'].append(_set_submitter(submitter, data_periods)) - - context['applicable_data_periods'] = sorted(context['applicable_data_periods'], reverse=True) - return context - - def get_template_names(self): - submitters = self.request.session.get("submitters") - - ## If no submitter_id for user should not show form but show error page - if submitters and all((submitter[0] is not None for submitter in submitters)): - return ["extension_submission_form/extension_submission_form.html"] - else: - return ["extension_submission_form/extension_err_no_sub_id.html"] def post(self, request): - if (request.user.is_authenticated) and has_apcd_group(request.user): - - form = request.POST.copy() - errors= [] - submitters = request.session.get('submitters') - - - max_iterations = 1 - - for i in range(2, 6): - ## Pick a element from the form to count iterations - if form.get('requested-target-date_{}'.format(i)): - max_iterations += 1 - else: - break - - for iteration in range(max_iterations): - submitter = next(submitter for submitter in submitters if int(submitter[0]) == int(form['business-name_{}'.format(iteration + 1)])) - exten_resp = apcd_database.create_extension(form, iteration + 1, submitter) - if _err_msg(exten_resp): - errors.append(_err_msg(exten_resp)) - - if len(errors): - template = loader.get_template('extension_submission_form/extension_submission_error.html') - response = HttpResponse(template.render({}, request)) + """ + Handle form submission and return JSON response for success/failure + """ + if request.user.is_authenticated and has_apcd_group(request.user): + form = json.loads(request.body) + extensions = form['extensions'] + errors = [] + submitters = apcd_database.get_submitter_info(request.user.username) + for extension in extensions: + submitter = next(submitter for submitter in submitters if int(submitter[0] == int(extension['businessName']))) + exten_resp = apcd_database.create_extension(form, extension, submitter) + if self._err_msg(exten_resp): + errors.append(self._err_msg(exten_resp)) + + # Return success or error as JSON + if errors: + logger.error("Extension request failed. Errors: %s", errors) + return JsonResponse({'status': 'error', 'errors': errors}, status=400) else: - template = loader.get_template('extension_submission_form/extension_form_success.html') - response = HttpResponse(template.render({}, request)) - - return response + return JsonResponse({'status': 'success'}, status=200) else: return HttpResponseRedirect('/') -def _get_applicable_data_period(value): - try: - return datetime.strptime(str(value), '%Y%m').strftime('%Y-%m') - except: - return None - -def _err_msg(resp): - if hasattr(resp, 'pgerror'): - return resp.pgerror - if isinstance(resp, Exception): - return str(resp) - return None - -def get_expected_date(request): - applicable_data_period = request.GET.get('applicable_data_period') - submitter_id = request.GET.get('submitter_id') - expected_date = apcd_database.get_current_exp_date(submitter_id=submitter_id, applicable_data_period=applicable_data_period) - - return JsonResponse(expected_date, safe=False) \ No newline at end of file + def _err_msg(self, resp): + """ + Helper function to extract error messages + """ + if hasattr(resp, 'pgerror'): + return resp.pgerror + if isinstance(resp, Exception): + return str(resp) + return None \ No newline at end of file diff --git a/apcd_cms/src/apps/registrations/static/registrations/css/submission_form.css b/apcd_cms/src/apps/registrations/static/registrations/css/submission_form.css index 515746e7..af57b8b5 100644 --- a/apcd_cms/src/apps/registrations/static/registrations/css/submission_form.css +++ b/apcd_cms/src/apps/registrations/static/registrations/css/submission_form.css @@ -1,16 +1,21 @@ /* Field Widths */ /* for an Entity*/ -input[name^="fein"], -input[name^="license_number"], -input[name^="naic_company_code"], +input[name*="fein"], +input[name*="license_number"], +input[name*="naic_company_code"], /* for an Organization */ input[name^="zip_code"] { width: 10ch; box-sizing: content-box; } +div.checkboxselectmultiple label, div.radioselect label { + align-items: center; + display: flex; + gap: .5em; +} /* for a Contact */ -input[name^="contact_phone"] { +input[name*="contact_phone"] { width: 17ch; box-sizing: content-box; } @@ -18,7 +23,7 @@ input[name^="contact_phone"] { /* Field Layouts */ /* To make (radio/check)box sets take up less vertical space */ -#types_of_files, #types_of_plans, #submission_method, #on-behalf-of { +div[id*="types_of_files"], div[id*="types_of_plans"], div[id*="submission_method"], div[id*="on_behalf_of"] { display: flex; flex-wrap: wrap; column-gap: 1em; @@ -40,11 +45,11 @@ input[name^="contact_phone"] { grid-template-columns: repeat( auto-fill, var(--max-col-width) ); max-width: calc( var(--global-space--grid-gap) + var(--max-col-width) * 2 ); } -.field-wrapper:has([id^="contact_email"]) { +.field-wrapper:has([id*="contact_email"]) { /* To mimic site.css `.help-text` margin-top */ margin-bottom: calc(var(--global-font-size--small) * 0.3); } -.field-wrapper:has([id^="contact_phone"]) { +.field-wrapper:has([id*="contact_phone"]) { /* To pull contact_notifications up against contact_email */ /* NOTE: A span 2 seems like enough, but only span 3+ does the job */ grid-row: span 3; diff --git a/apcd_cms/src/apps/registrations/templates/registration_form.html b/apcd_cms/src/apps/registrations/templates/registration_form.html new file mode 100644 index 00000000..494cd670 --- /dev/null +++ b/apcd_cms/src/apps/registrations/templates/registration_form.html @@ -0,0 +1,18 @@ +{% extends "apcd_cms/templates/standard.html" %} +{% load static %} + +{% block content %} + + + + +
+ {% include "nav_cms_breadcrumbs.html" %} + + +
+
+
+ + {# Footnotes #} +{% endblock %} diff --git a/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_body.html b/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_body.html index 5167beba..af6d9265 100644 --- a/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_body.html +++ b/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_body.html @@ -4,20 +4,6 @@ {% if r %} - - {% if not renew %} - -
- -
- {% endif %} - {% endif %} @@ -463,7 +449,7 @@
class="integerfield" id="total_covered_lives_{{ent_no}}_{{r.reg_id}}" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)$" + pattern="^[1-9]+[0-9]*$" value="{% if not renew %}{{ entity.no_covered }}{% endif %}" />
@@ -482,7 +468,7 @@
class="integerfield" id="claims_encounters_volume_{{ent_no}}_{{r.reg_id}}" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)$" + pattern="^[1-9]+[0-9]*$" value="{% if not renew %}{{ entity.claim_and_enc_vol }}{% endif %}" /> @@ -506,7 +492,7 @@
class="integerfield" id="total_claims_value_{{ent_no}}_{{r.reg_id}}" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$" + pattern="^(?=.*[1-9])[0-9]*[.]?[0-9]{1,2}$" value="{% if not renew %}{{ entity.claim_val }}{% endif %}" />
@@ -760,7 +746,7 @@
class="integerfield" id="total_covered_lives_1" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)$" + pattern="^[1-9]+[0-9]*$" />
@@ -778,7 +764,7 @@
class="integerfield" id="claims_encounters_volume_1" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)$" + pattern="^[1-9]+[0-9]*$" />
@@ -801,7 +787,7 @@
class="integerfield" id="total_claims_value_1" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$" + pattern="^(?=.*[1-9])[0-9]*[.]?[0-9]{1,2}$" />
{# Additional entities rendered here... #} diff --git a/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_scripts.html b/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_scripts.html index c525b582..ba1458da 100644 --- a/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_scripts.html +++ b/apcd_cms/src/apps/registrations/templates/submission_form/registration_form_scripts.html @@ -316,7 +316,7 @@
class="integerfield" id="total_covered_lives_${entities}${reg_id_substr}" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)$" + pattern="^[1-9]+[0-9]*$" />
@@ -333,7 +333,7 @@
class="integerfield" id="claims_encounters_volume_${entities}${reg_id_substr}" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)$" + pattern="^[1-9]+[0-9]*$" />
Enter a whole number. @@ -352,7 +352,7 @@
class="integerfield" id="total_claims_value_${entities}${reg_id_substr}" inputmode="numeric" - pattern="^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$" + pattern="^(?=.*[1-9])[0-9]*[.]?[0-9]{1,2}$" />
diff --git a/apcd_cms/src/apps/registrations/templates/submission_form/submission_form.html b/apcd_cms/src/apps/registrations/templates/submission_form/submission_form.html deleted file mode 100644 index c15de247..00000000 --- a/apcd_cms/src/apps/registrations/templates/submission_form/submission_form.html +++ /dev/null @@ -1,85 +0,0 @@ -{% extends "standard.html" %} -{% load static %} - -{% block content %} - - - -
- {% include "nav_cms_breadcrumbs.html" %} - {% include 'snippets/tup-175-css-alerts-messages-ui-pattern.html' %} - - - -
-
-

Request to Submit

-
- -

- This form should be completed and submitted to register as a data - submitter. Please review the - Data Submission Guide for details about completing and submitting this form, paying - special attention to the schedule of submissions including test files, - historical files, and monthly files. -

- -
- -
-
-

Organization

-
- -
- {% include "submission_form/registration_form_body.html" %} -
- -
- - {# Hidden links for future pages #} - {# TODO: Allow this template to render CMS admin-entered markup #} - - - {# Scripts #} - {# WARNING: Many are cruft that created this now-static markup, but not all #}{# TODO: FP-1888: Clean out the cruft #} - {% include "submission_form/registration_form_scripts.html" %} - - {# Footnotes #} -
-
-

- ¹ Third Party Administrator / Administrative Services Only (TPA/ASO)
- ² Federal Employer Identification Number (FEIN)
- ³ National Association of Insurance Commissioners (NAIC)
- ⁴ United States Dollar (USD)
-
-

-
-

- * Eligibility/Enrollment files are mandatory along with any combination - of claims files. -

-
-
-{% endblock %} diff --git a/apcd_cms/src/apps/registrations/urls.py b/apcd_cms/src/apps/registrations/urls.py index 8d2d7b1d..8fdf6cf7 100644 --- a/apcd_cms/src/apps/registrations/urls.py +++ b/apcd_cms/src/apps/registrations/urls.py @@ -1,7 +1,9 @@ from django.urls import path -from apps.registrations.views import SubmissionFormView +from django.views.generic import TemplateView +from apps.registrations.views import RegistrationFormView app_name = 'registrations' urlpatterns = [ - path('request-to-submit/', SubmissionFormView.as_view(), name='register_table') + path('request-to-submit/', TemplateView.as_view(template_name='registration_form.html'), name='register_form'), + path('request-to-submit/api/', RegistrationFormView.as_view(), name='register_form_api'), ] diff --git a/apcd_cms/src/apps/registrations/views.py b/apcd_cms/src/apps/registrations/views.py index 266ebe1e..b25516f7 100644 --- a/apcd_cms/src/apps/registrations/views.py +++ b/apcd_cms/src/apps/registrations/views.py @@ -1,12 +1,11 @@ -from apps.utils import apcd_database +from apps.utils.apcd_database import create_registration, create_registration_entity, create_registration_contact, get_registrations, get_registration_entities, get_registration_contacts from apps.utils.apcd_groups import has_apcd_group from apps.utils.registrations_data_formatting import _set_registration from apps.submitter_renewals_listing.views import get_submitter_code from apps.utils.apcd_groups import has_groups from django.conf import settings -from django.http import HttpResponse, HttpResponseRedirect -from django.template import loader -from django.views.generic import View +from django.http import HttpResponseRedirect, JsonResponse +from django.views.generic import TemplateView from django.shortcuts import redirect from requests.auth import HTTPBasicAuth import logging @@ -21,36 +20,35 @@ RT_QUEUE = getattr(settings, 'RT_QUEUE', '') -class SubmissionFormView(View): +class RegistrationFormView(TemplateView): def get(self, request): formatted_reg_data = [] renew = False - reg_id = request.GET.get('reg_id', None) + reg_id = request.GET.get('reg_id', None).rstrip('/') # reg_id coming from renew has trailing slash appended, need to remove to pass correct request through if reg_id and (has_groups(request.user, ['APCD_ADMIN', 'SUBMITTER_ADMIN'])): try: response = get_submitter_code(request.user) submitter_code = json.loads(response.content)['submitter_code'] - submitter_registrations = apcd_database.get_registrations(submitter_code=submitter_code) + submitter_registrations = get_registrations(submitter_code=submitter_code) registration_content = [registration for registration in submitter_registrations if registration[0] == int(reg_id)][0] - registration_entities = apcd_database.get_registration_entities(reg_id=reg_id) - registration_contacts = apcd_database.get_registration_contacts(reg_id=reg_id) + registration_entities = get_registration_entities(reg_id=reg_id) + registration_contacts = get_registration_contacts(reg_id=reg_id) renew = True formatted_reg_data = _set_registration(registration_content, registration_entities, registration_contacts) except Exception as exception: logger.error(exception) return redirect('/register/request-to-submit/') if (request.user.is_authenticated and has_apcd_group(request.user)): - template = loader.get_template('submission_form/submission_form.html') - return HttpResponse(template.render({'r': formatted_reg_data, 'renew': renew}, request)) + context = {'registration_data': formatted_reg_data, 'renew': renew} + return JsonResponse({'response': context}) return HttpResponseRedirect('/') - def post(self, request): - form = request.POST.copy() - old_reg_id = None + form = json.loads(request.body) + entities = form['entities'] + contacts = form['contacts'] renewal = False if 'reg_id' in form: - old_reg_id = form['reg_id'] renewal = True errors = [] @@ -62,17 +60,18 @@ def post(self, request): else: return HttpResponseRedirect('/') - reg_resp = apcd_database.create_registration(form, renewal=renewal) + reg_resp = create_registration(form, renewal=renewal) if not _err_msg(reg_resp) and type(reg_resp) == int: - for iteration in range(1,6): - contact_resp = apcd_database.create_registration_contact(form, reg_resp, iteration, old_reg_id=old_reg_id) - entity_resp = apcd_database.create_registration_entity(form, reg_resp, iteration, old_reg_id=old_reg_id) - if _err_msg(contact_resp): - errors.append(_err_msg(contact_resp)) - if _err_msg(entity_resp): - errors.append(_err_msg(entity_resp)) + for entity in entities: + entity_resp = create_registration_entity(entity, reg_resp) + if entity_resp: # only returns a value if error occurs + errors.append(str(entity_resp)) + for contact in contacts: + contact_resp = create_registration_contact(contact, reg_resp) + if contact_resp: # only returns a value if error occurs + errors.append(str(contact_resp)) else: - errors.append(_err_msg(reg_resp)) + errors.append(str(reg_resp)) # ===> Create Ticket tracker = rt.Rt(RT_HOST, RT_UN, RT_PW, http_auth=HTTPBasicAuth(RT_UN, RT_PW)) @@ -90,19 +89,22 @@ def post(self, request): description += "Error(s):\n" for err_msg in errors: description += "{}\n".format(err_msg) - template = loader.get_template('submission_form/submission_error.html') - response = HttpResponse(template.render({}, request)) + response = JsonResponse({'status': 'error', 'errors': errors}, status=400) else: - context = {'reg_id': reg_resp} - template = loader.get_template('submission_form/submission_success.html') - response = HttpResponse(template.render(context, request)) - - tracker.create_ticket( - Queue=RT_QUEUE, - Subject=subject, - Text=description, - Requestors=email - ) + response = JsonResponse({'status': 'success', 'reg_id': reg_resp}, status=200) + try: + tracker.create_ticket( + Queue=RT_QUEUE, + Subject=subject, + Text=description, + Requestor=email + ) + except Exception as err: + msg = "Could not create ticket for new TX-APCD Registration Request" + logger.exception(msg=msg) + logger.error(err.args) + errors.append(str(msg)) + response = JsonResponse({'status': 'error', 'errors': errors}, status=400) return response diff --git a/apcd_cms/src/apps/submissions/static/submissions/css/table.css b/apcd_cms/src/apps/submissions/static/submissions/css/table.css index e31c3e95..534fbda5 100644 --- a/apcd_cms/src/apps/submissions/static/submissions/css/table.css +++ b/apcd_cms/src/apps/submissions/static/submissions/css/table.css @@ -6,10 +6,12 @@ @media (max-width: 767px) { /* To label the cells */ /* RFE: Add `data-label` to each cell so we can use `attr(data-label)` */ - .submission-table td:nth-of-type(1):before { content: "Submission ID"; } - .submission-table td:nth-of-type(2):before { content: "File Name"; } - .submission-table td:nth-of-type(3):before { content: "Status"; } + .submission-table td:nth-of-type(1):before { content: "Received"; } + .submission-table td:nth-of-type(2):before { content: "Organization"; } + .submission-table td:nth-of-type(3):before { content: "File Name"; } .submission-table td:nth-of-type(4):before { content: "Outcome"; } - .submission-table td:nth-of-type(5):before { content: "Created"; } - .submission-table td:nth-of-type(7):before { content: "Actions"; } + .submission-table td:nth-of-type(5):before { content: "Status"; } + .submission-table td:nth-of-type(6):before { content: "Last Updated"; } + .submission-table td:nth-of-type(7):before { content: "Payor Code"; } + .submission-table td:nth-of-type(8):before { content: "Actions"; } } diff --git a/apcd_cms/src/apps/submissions/templates/list_submissions.html b/apcd_cms/src/apps/submissions/templates/list_submissions.html index 25106db0..012ebdcf 100644 --- a/apcd_cms/src/apps/submissions/templates/list_submissions.html +++ b/apcd_cms/src/apps/submissions/templates/list_submissions.html @@ -1,4 +1,4 @@ -{% extends "standard.html" %} +{% extends "apcd_cms/templates/standard.html" %} {% load static %} {% block content %} @@ -12,96 +12,9 @@
{% include "nav_cms_breadcrumbs.html" %} -

View Submissions

+

User Submissions


A list of submissions by a user


-
-
- Filter by Status: - - Sort by: - - {% if selected_status != 'All' or selected_sort != None %} - - {% endif %} -
-
- - - - - {% for k in header %} - - {% endfor %} - - - - {% for r in page %} - - - - - - - - - {% endfor %} - -
{{k}}
{{r.received_timestamp}}{{r.file_name}}{{r.outcome}}{{r.status}}{{r.updated_at}} - {% include "view_submission_logs_modal.html" %} - View Logs -
- - {% include 'paginator.html' %} -
- +
{% endblock %} diff --git a/apcd_cms/src/apps/submissions/urls.py b/apcd_cms/src/apps/submissions/urls.py index a89ce4ba..9b2865a2 100644 --- a/apcd_cms/src/apps/submissions/urls.py +++ b/apcd_cms/src/apps/submissions/urls.py @@ -1,11 +1,12 @@ from django.urls import path +from django.views.generic import TemplateView from apps.submissions.views import SubmissionsTable, check_submitter_role app_name = 'submissions' urlpatterns = [ - path('list-submissions/', SubmissionsTable.as_view(), name="list_submissions"), - path(r'list-submissions/?status=(?P)/', SubmissionsTable.as_view(), name="list_submissions"), - path(r'list-submissions/?sort=(?P)/', SubmissionsTable.as_view(), name="list_submissions"), - path(r'list-submissions/?sort=(?P)&status=(?P)/', SubmissionsTable.as_view(), name="list_submissions"), + path('list-submissions/', TemplateView.as_view(template_name='list_submissions.html'), name="list_submissions"), + path('list-submissions/api/', SubmissionsTable.as_view(), name="list_submissions_api"), + path('list-submissions/api/options', SubmissionsTable.as_view(), name="list_submissions_api_options"), + path('view_log', SubmissionsTable.as_view(), name='submission-view-log'), path('check-submitter-role/', check_submitter_role), -] +] \ No newline at end of file diff --git a/apcd_cms/src/apps/submissions/views.py b/apcd_cms/src/apps/submissions/views.py index e6101333..bb1a6daf 100644 --- a/apcd_cms/src/apps/submissions/views.py +++ b/apcd_cms/src/apps/submissions/views.py @@ -3,8 +3,9 @@ from django.contrib.auth.decorators import login_required from apps.utils.apcd_database import get_user_submissions_and_logs from apps.utils.apcd_groups import has_apcd_group -from apps.utils.utils import title_case, table_filter -from apps.components.paginator.paginator import paginator +from apps.utils.utils import title_case +from apps.admin_submissions.views import SubmissionsLogView +from django.core.paginator import Paginator import logging from dateutil import parser @@ -20,61 +21,97 @@ def dispatch(self, request, *args, **kwargs): return HttpResponseRedirect('/') return super(SubmissionsTable, self).dispatch(request, *args, **kwargs) - def get_context_data(self, *args, **kwargs): - - context = super(SubmissionsTable, self).get_context_data(*args, **kwargs) - - user = self.request.user.username - - submission_content = get_user_submissions_and_logs(user) - - queryStr = '' - dateSort = self.request.GET.get('sort') - status_filter = self.request.GET.get('status') - - def getDate(row): - date = row['received_timestamp'] - return parser.parse(date) if date is not None else parser.parse('1-1-3005') # put 'None' date entries all together at top/bottom depending on direction of sort - - if dateSort is not None: - context['selected_sort'] = dateSort - queryStr += f'&sort={dateSort}' - submission_content = sorted(submission_content, key=lambda row:getDate(row), reverse=(dateSort == 'newDate')) - + def get(self, request, *args, **kwargs): + if 'options' in request.path: + return self.get_options(request) + if 'view_log' in request.path: + return SubmissionsLogView.get_log(request) + + status = request.GET.get('status', 'All') + sort = request.GET.get('sort', 'Newest Received') + submitter_id = request.GET.get('submitterId', 'All') + payor_code = request.GET.get('payorCode', 'All') + page_number = int(request.GET.get('page', 1)) + items_per_page = int(request.GET.get('limit', 50)) + + try: + submission_content = get_user_submissions_and_logs(request.user.username) + filtered_submissions = self.filtered_submissions(submission_content, status, sort, submitter_id, payor_code) + + paginator = Paginator(filtered_submissions, items_per_page) + page_info = paginator.get_page(page_number) + context = self.get_view_submissions_json(list(page_info), selected_status=status, selected_sort=sort) + context['page_num'] = page_info.number + context['total_pages'] = paginator.num_pages + return JsonResponse({'response': context}) + except Exception as e: + logger.error("Error fetching filtered user data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context.update(self.get_view_submissions_json(get_user_submissions_and_logs(self.request.user.username))) + return context + + def get_options(self, request): try: - page_num = int(self.request.GET.get('page')) - except: - page_num = 1 - - context['selected_status'] = 'All' - if status_filter is not None and status_filter != 'All': - context['selected_status'] = status_filter - queryStr += f'&status={status_filter}' - submission_content = table_filter(status_filter, submission_content, 'status') - - limit = 50 - offset = limit * (page_num - 1) - - # modifies the object fields for display, only modifies a subset of entries that will be displayed - # on the current page using offset and limit - for s in submission_content[offset:offset + limit]: - s['status'] = title_case(s['status']) if s['status'] else None - s['outcome'] = title_case(s['outcome']) if s['outcome'] else None - s['received_timestamp'] = parser.parse(s['received_timestamp']) if s['received_timestamp'] else None - s['updated_at'] = parser.parse(s['updated_at']) if s['updated_at'] else None - s['view_modal_content'] = [{ - **t, - 'outcome': title_case(t['outcome']) if t['outcome'] else None - } for t in (s['view_modal_content'] or [])] - - - context['header'] = ['Received', 'File Name', ' ', 'Outcome', 'Status', 'Last Updated', 'Actions'] - context['status_options'] = ['All', 'Complete', 'In Process'] - context['sort_options'] = {'newDate': 'Newest Received', 'oldDate': 'Oldest Received'} - - context['query_str'] = queryStr - context.update(paginator(self.request, submission_content, limit)) - context['pagination_url_namespaces'] = 'submissions:list_submissions' + status_options = ['All', 'In Process', 'Complete'] + sort_options = [{'name': 'Newest Received', 'value': 'newDate'}, + {'name': 'Oldest Received', 'value': 'oldDate'}] + + return JsonResponse({ + 'status_options': status_options, + 'sort_options': sort_options, + }) + except Exception as e: + logger.error("Error fetching options data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + def filtered_submissions(self, submission_content, status, sort, submitter_id, payor_code): + def getDate(submission): + date = submission['received_timestamp'] + return parser.parse(date) if date is not None else parser.parse('1-1-3005') + + if status != 'All': + submission_content = [submission for submission in submission_content + if submission['status'].lower() == status.lower()] + + if submitter_id != 'All': + submission_content = [submission for submission in submission_content + if submission['submitter_id'] == int(submitter_id)] + if payor_code != 'All': + submission_content = [submission for submission in submission_content + if submission['payor_code'] == int(payor_code)] + submission_content = sorted( + submission_content, + key=lambda row: getDate(row), + reverse=(sort == 'Newest Received') + ) + return submission_content + + def get_view_submissions_json(self, submission_content, selected_status='All', selected_sort='Newest Received', submission_id='All', payor_code='All'): + context = { + 'page': [], + 'selected_status': selected_status, + 'selected_sort': selected_sort, + 'pagination_url_namespaces':'submissions:list_submissions' + } + + def _set_submissions(submission): + return { + 'submission_id': submission['submission_id'], + 'submitter_id': submission['submitter_id'], + 'file_name': submission['file_name'], + 'status': submission['status'], + 'outcome': title_case(submission['outcome']) if submission['outcome'] else None, + 'received_timestamp': submission['received_timestamp'], + 'updated_at': submission['updated_at'], + 'payor_code': submission['payor_code'], + 'entity_name': submission['entity_name'], + 'view_modal_content': submission['view_modal_content'], + } + for submission in submission_content: + context['page'].append(_set_submissions(submission)) return context @@ -83,4 +120,4 @@ def getDate(row): def check_submitter_role(request): logger.info("Checking submitter access for user: %s", request.user.username) - return JsonResponse({"is_submitter": has_apcd_group(request.user)}) + return JsonResponse({"is_submitter": has_apcd_group(request.user)}) \ No newline at end of file diff --git a/apcd_cms/src/apps/submitter_renewals_listing/templates/list_submitter_registrations.html b/apcd_cms/src/apps/submitter_renewals_listing/templates/list_submitter_registrations.html index fd486192..4600d86d 100644 --- a/apcd_cms/src/apps/submitter_renewals_listing/templates/list_submitter_registrations.html +++ b/apcd_cms/src/apps/submitter_renewals_listing/templates/list_submitter_registrations.html @@ -1,4 +1,4 @@ -{% extends "standard.html" %} +{% extends "apcd_cms/templates/standard.html" %} {% load static %} {% block content %} @@ -14,115 +14,6 @@

Registration Information


Current registration information on file for your organization is listed below. On the right of the screen, select the dropdown menu under “Actions” to view or renew your organization’s registration information.


-
-
- Filter by Status: - - Filter by Organization: - - {% if selected_status or selected_org %} - - {% endif %} -
-
- - - - {% for k in header %} - - {% endfor %} - - - - {% for r in page %} - - - - - - - - - {% endfor %} - -
{{k}}
{{r.biz_name}}{{r.year}}{{r.type}}{{r.location}}{{r.reg_status}} - {% include "view_registration_modal.html" %} - -
- {% include 'paginator.html' %} +
- - {% endblock %} diff --git a/apcd_cms/src/apps/submitter_renewals_listing/templates/submitter_listing_error.html b/apcd_cms/src/apps/submitter_renewals_listing/templates/submitter_listing_error.html deleted file mode 100644 index 503e7b92..00000000 --- a/apcd_cms/src/apps/submitter_renewals_listing/templates/submitter_listing_error.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "standard.html" %} -{% block content %} -
- {% include "nav_cms_breadcrumbs.html" %} - -

View Registations

-
-

- An error occurred loading your registrations. For help, submit a ticket. -

- Back to Home -
- -{% endblock %} diff --git a/apcd_cms/src/apps/submitter_renewals_listing/urls.py b/apcd_cms/src/apps/submitter_renewals_listing/urls.py index bd43d3c5..c03c1f34 100644 --- a/apcd_cms/src/apps/submitter_renewals_listing/urls.py +++ b/apcd_cms/src/apps/submitter_renewals_listing/urls.py @@ -1,10 +1,9 @@ from django.urls import path +from django.views.generic import TemplateView from apps.submitter_renewals_listing.views import SubmittersTable app_name = 'register' urlpatterns = [ - path('list-registration-requests/', SubmittersTable.as_view(), name='submitter_regis_table'), - path(r'list-registration-requests/?status=(?P)/', SubmittersTable.as_view(), name='submitter_regis_table'), - path(r'list-registration-requests/?org=(?P)/', SubmittersTable.as_view(), name='submitter_regis_table'), - path(r'list-registration-requests/?status=(?P)&org=(?P)/', SubmittersTable.as_view(), name='submitter_regis_table') + path('list-registration-requests/', TemplateView.as_view(template_name='list_submitter_registrations.html'), name='submitter_regis_table'), + path('list-registration-requests/api/', SubmittersTable.as_view(), name='submitter_regis_table_api'), ] diff --git a/apcd_cms/src/apps/submitter_renewals_listing/views.py b/apcd_cms/src/apps/submitter_renewals_listing/views.py index 636150a3..698cca0f 100644 --- a/apcd_cms/src/apps/submitter_renewals_listing/views.py +++ b/apcd_cms/src/apps/submitter_renewals_listing/views.py @@ -2,7 +2,9 @@ from django.template import loader from apps.utils.apcd_database import get_registrations, get_registration_contacts, get_submitter_info, get_registration_entities from apps.utils.apcd_groups import has_groups +from django.views.generic.base import TemplateView from apps.admin_regis_table.views import RegistrationsTable +from apps.utils.registrations_data_formatting import _set_registration import logging import json @@ -12,6 +14,13 @@ class SubmittersTable(RegistrationsTable): template_name = 'list_submitter_registrations.html' + def _get_first_registration_entry(self, submitter_code, reg_id): + registrations = get_registrations(submitter_code=submitter_code, reg_id=reg_id) + if len(registrations) > 0: + return registrations[0] + else: + raise Exception(f'Registration not found {reg_id}') + def get(self, request, *args, **kwargs): try: response = get_submitter_code(request.user) @@ -19,43 +28,40 @@ def get(self, request, *args, **kwargs): registrations_content = [] registrations_entities = [] registrations_contacts = [] - registration_list = get_registrations(submitter_code=submitter_code) - for registration in registration_list: - registrations_content.append(registration) - context = self.get_context_data(registrations_content, registrations_entities, registrations_contacts, *args,**kwargs) - template = loader.get_template(self.template_name) - return HttpResponse(template.render(context, request)) + if request.GET.get('reg_id'): + reg_id = int(request.GET.get('reg_id')) + registration = self._get_first_registration_entry(submitter_code=submitter_code, reg_id=reg_id) + registrations_entities = get_registration_entities(reg_id=reg_id) + registrations_contacts = get_registration_contacts(reg_id=reg_id) + return JsonResponse({'response': _set_registration(registration, registrations_entities, registrations_contacts)}) + else: + registration_list = get_registrations(submitter_code=submitter_code) + for registration in registration_list: + registrations_content.append(registration) + response_json = self.get_registration_list_json(registrations_content, *args, **kwargs) + return JsonResponse({'response': response_json}) except Exception as e: - logger.error("An error occurred: %s", str(e)) - context = super(RegistrationsTable, self).get_context_data(*args, **kwargs) - template = loader.get_template('submitter_listing_error.html') - return HttpResponse(template.render(context, request)) + logger.error("An error occurred in submitter registration GET request: %s", str(e)) + return JsonResponse({ + 'status': 'error', + 'message': 'Internal server error', + }, status=500) def dispatch(self, request, *args, **kwargs): if not request.user.is_authenticated or not (has_groups(request.user, ['APCD_ADMIN', 'SUBMITTER_ADMIN'])): return HttpResponseRedirect('/') return super(RegistrationsTable, self).dispatch(request, *args, **kwargs) - def get_context_data(self, registrations_content, registrations_entities, registrations_contacts, *args, **kwargs): - registrations_entities = [] - registrations_contacts = [] + def get_registration_list_json(self, registrations_content, *args, **kwargs): try: - for registration in registrations_content: - reg_id = registration[0] - contacts = get_registration_contacts(reg_id=reg_id) - entity = get_registration_entities(reg_id=reg_id) - for c in contacts: - registrations_contacts.append(c) - for e in entity: - registrations_entities.append(e) - context = super().get_context_data(registrations_content, registrations_entities, registrations_contacts, *args, **kwargs) - context['header'] = ['Business Name', 'Year', 'Type', 'Location', 'Registration Status', 'Actions'] - context['pagination_url_namespaces'] = 'register:submitter_regis_table' - return context + reg_data = super().get_registration_list_json(registrations_content, *args, **kwargs) + reg_data['header'] = ['Business Name', 'Year', 'Type', 'Location', 'Registration Status', 'Actions'] + reg_data['pagination_url_namespaces'] = 'register:submitter_regis_table' + return reg_data except Exception as e: - logger.error("A context error occurred: %s", str(e)) - context = super(RegistrationsTable, self).get_context_data(*args, **kwargs) - return context + logger.error("A data loading error occurred: %s", str(e)) + reg_data = super(RegistrationsTable, self).get_registration_list_json(*args, **kwargs) + return reg_data def get_submitter_code(request): @@ -63,4 +69,4 @@ def get_submitter_code(request): submitter_codes = [] for i in submitter: submitter_codes.append(i[1]) - return JsonResponse({'submitter_code' : submitter_codes} if submitter_codes else [], safe=False) + return JsonResponse({'submitter_code': submitter_codes} if submitter_codes else [], safe=False) diff --git a/apcd_cms/src/apps/utils/apcd_database.py b/apcd_cms/src/apps/utils/apcd_database.py index f49a4ef3..75f0188f 100644 --- a/apcd_cms/src/apps/utils/apcd_database.py +++ b/apcd_cms/src/apps/utils/apcd_database.py @@ -9,6 +9,17 @@ APCD_DB = settings.APCD_DATABASE +def db_connect(): + return psycopg.connect( + host=APCD_DB['host'], + dbname=APCD_DB['database'], + user=APCD_DB['user'], + password=APCD_DB['password'], + port=APCD_DB['port'], + sslmode='require' + ) + + def get_users(): cur = None conn = None @@ -38,7 +49,7 @@ def get_users(): LEFT JOIN submitter_users ON users.user_id = submitter_users.user_id AND users.user_number = submitter_users.user_number LEFT JOIN submitters on submitter_users.submitter_id = submitters.submitter_id - ORDER BY submitters.entity_name ASC; + ORDER BY submitters.entity_name, users.user_id ASC; """ cur = conn.cursor() cur.execute(query) @@ -52,7 +63,7 @@ def get_users(): cur.close() if conn is not None: conn.close() - + def update_user(form): cur = None conn = None @@ -141,6 +152,48 @@ def get_user_role(user): if conn is not None: conn.close() +def get_submitter_users(): + cur = None + conn = None + try: + conn = db_connect() + query = """ + SELECT DISTINCT submitter_users.submitter_id, + submitter_users.user_id, + users.user_name, + users.org_name, + roles.role_name, + users.active, + users.user_number, + submissions.payor_code, + users.role_id, + users.user_email, + users.notes, + submitters.org_name + FROM submitter_users + JOIN users + ON submitter_users.user_id = users.user_id + AND submitter_users.user_number = users.user_number + JOIN submissions + ON submitter_users.submitter_id = submissions.submitter_id + JOIN roles + ON roles.role_id = users.role_id + JOIN submitters + ON submitter_users.submitter_id = submitters.submitter_id + ORDER BY submitter_users.user_id; + """ + cur = conn.cursor() + cur.execute(query) + return cur.fetchall() + + except Exception as error: + logger.error(error) + + finally: + if cur is not None: + cur.close() + if conn is not None: + conn.close() def get_registrations(reg_id=None, submitter_code=None): cur = None @@ -166,9 +219,12 @@ def get_registrations(reg_id=None, submitter_code=None): registrations.state, registrations.zip, registrations.registration_year - FROM registrations - {f"WHERE registration_id = {str(reg_id)}" if reg_id is not None else ''} - {f"LEFT JOIN registration_submitters on registrations.registration_id = registration_submitters.registration_id LEFT JOIN submitters ON registration_submitters.submitter_id = submitters.submitter_id WHERE submitter_code = ANY(%s) ORDER BY registrations.registration_id" if submitter_code is not None else ''}""" + FROM registrations + {f"LEFT JOIN registration_submitters ON registrations.registration_id = registration_submitters.registration_id LEFT JOIN submitters ON registration_submitters.submitter_id = submitters.submitter_id" if submitter_code is not None else ''} + WHERE 1=1 + {f" AND registrations.registration_id = {str(reg_id)}" if reg_id is not None else ''} + {f" AND submitters.submitter_code = ANY(%s)" if submitter_code is not None else ''} + ORDER BY registrations.registration_id""" cur = conn.cursor() if submitter_code: cur.execute(query, (submitter_code,)) @@ -214,11 +270,11 @@ def create_registration(form, renewal=False): RETURNING registration_id""" values = ( datetime.now(), - True if form['on-behalf-of'] == 'true' else False, + True if form['on_behalf_of'] == 'true' else False, 'Received', form['type'], - _clean_value(form['business-name']), - _clean_value(form['mailing-address']), + _clean_value(form['business_name']), + _clean_value(form['mailing_address']), _clean_value(form['city']), form['state'][:2], form['zip_code'], @@ -267,11 +323,11 @@ def update_registration(form, reg_id): WHERE registration_id = %s RETURNING registration_id""" values = ( - True if form['on-behalf-of'] == 'true' else False, + True if form['on_behalf_of'] == 'true' else False, form['reg_status'], form['type'], - _clean_value(form['business-name']), - _clean_value(form['mailing-address']), + _clean_value(form['business_name']), + _clean_value(form['mailing_address']), _clean_value(form['city']), form['state'][:2], form['zip_code'], @@ -339,31 +395,31 @@ def get_registration_entities(reg_id=None, submitter_code=None): conn.close() -def create_registration_entity(form, reg_id, iteration, from_update_reg=None, old_reg_id=None): +def create_registration_entity(entity, reg_id, from_update_reg=None):#, old_reg_id=None): cur = None conn = None values = () try: - if not _acceptable_entity(form, iteration, reg_id if from_update_reg else (old_reg_id if old_reg_id else None)): - return - str_end = f'{iteration}{ f"_{reg_id}" if from_update_reg else (f"_{old_reg_id}" if old_reg_id else "") }' + #if not _acceptable_entity(form, iteration, reg_id if from_update_reg else (old_reg_id if old_reg_id else None)): + # return + #str_end = f'{iteration}{ f"_{reg_id}" if from_update_reg else (f"_{old_reg_id}" if old_reg_id else "") }' values = ( reg_id, - float(form['total_claims_value_{}'.format(str_end)]), - _set_int(form['claims_encounters_volume_{}'.format(str_end)]), - form['license_number_{}'.format(str_end)] if len(form['license_number_{}'.format(str_end)]) else None, - form['naic_company_code_{}'.format(str_end)] if len(form['naic_company_code_{}'.format(str_end)]) else None, - _set_int(form['total_covered_lives_{}'.format(str_end)]), - _clean_value(form['entity_name_{}'.format(str_end)]), - _clean_value(form['fein_{}'.format(str_end)]), - True if 'types_of_plans_commercial_{}'.format(str_end) in form else False, - True if 'types_of_plans_medicare_{}'.format(str_end) in form else False, - True if 'types_of_plans_medicaid_{}'.format(str_end) in form else False, + float(entity['total_claims_value']), + _set_int(entity['claims_encounters_volume']), + _set_int(entity['license_number']), + _set_int(entity['naic_company_code']), + _set_int(entity['total_covered_lives']), + _clean_value(entity['entity_name']), + _clean_value(entity['fein']), + entity['types_of_plans_commercial'], + entity['types_of_plans_medicare'], + entity['types_of_plans_medicaid'], True, - True if 'types_of_files_provider_{}'.format(str_end) in form else False, - True if 'types_of_files_medical_{}'.format(str_end) in form else False, - True if 'types_of_files_pharmacy_{}'.format(str_end) in form else False, - True if 'types_of_files_dental_{}'.format(str_end) in form else False + entity['types_of_files_provider'], + entity['types_of_files_medical'], + entity['types_of_files_pharmacy'], + entity['types_of_files_dental'] ) operation = """INSERT INTO registration_entities( @@ -408,35 +464,32 @@ def create_registration_entity(form, reg_id, iteration, from_update_reg=None, ol conn.close() -def update_registration_entity(form, reg_id, iteration, no_entities): +def update_registration_entity(entity, reg_id): cur = None conn = None values = () try: - str_end = f'{iteration}_{reg_id}' - if not _acceptable_entity(form, iteration, reg_id): - if iteration <= no_entities: # entity is not in form but was in original entity list -> need to delete - return delete_registration_entity(reg_id, form['ent_id_{}'.format(str_end)]) - return - if iteration > no_entities: # entity is in form but not in original list -> need to create - return create_registration_entity(form, reg_id, iteration, from_update_reg=True) + # if entity_id is not there or is less than 0, then + # it is a new entity. + if 'entity_id' not in entity or entity['entity_id'] < 0: + return create_registration_entity(entity, reg_id) values = ( - float(form['total_claims_value_{}'.format(str_end)]), - _set_int(form['claims_encounters_volume_{}'.format(str_end)]), - form['license_number_{}'.format(str_end)] if len(form['license_number_{}'.format(str_end)]) else None, - form['naic_company_code_{}'.format(str_end)] if len(form['naic_company_code_{}'.format(str_end)]) else None, - _set_int(form['total_covered_lives_{}'.format(str_end)]), - _clean_value(form['entity_name_{}'.format(str_end)]), - _clean_value(form['fein_{}'.format(str_end)]), - True if 'types_of_plans_commercial_{}'.format(str_end) in form else False, - True if 'types_of_plans_medicare_{}'.format(str_end) in form else False, - True if 'types_of_plans_medicaid_{}'.format(str_end) in form else False, - True if 'types_of_files_provider_{}'.format(str_end) in form else False, - True if 'types_of_files_medical_{}'.format(str_end) in form else False, - True if 'types_of_files_pharmacy_{}'.format(str_end) in form else False, - True if 'types_of_files_dental_{}'.format(str_end) in form else False, + float(entity['total_claims_value']), + _set_int(entity['claims_encounters_volume']), + _set_int(entity['license_number']), + _set_int(entity['naic_company_code']), + _set_int(entity['total_covered_lives']), + _clean_value(entity['entity_name']), + _clean_value(entity['fein']), + entity['types_of_plans_commercial'], + entity['types_of_plans_medicare'], + entity['types_of_plans_medicaid'], + entity['types_of_files_provider'], + entity['types_of_files_medical'], + entity['types_of_files_pharmacy'], + entity['types_of_files_dental'], reg_id, - form['ent_id_{}'.format(str_end)] + entity['entity_id'] ) conn = psycopg.connect( host=APCD_DB['host'], @@ -550,33 +603,23 @@ def get_registration_contacts(reg_id=None, submitter_code=None): conn.close() -def create_registration_contact(form, reg_id, iteration, from_update_reg=None, old_reg_id=None): +def create_registration_contact(contact, reg_id, from_update_reg=None): cur = None conn = None values = () try: - if iteration > 1: - if not _acceptable_contact(form, iteration, reg_id if from_update_reg else (old_reg_id if old_reg_id else None)): - return - str_end = f'{iteration}{ f"_{reg_id}" if from_update_reg else (f"_{old_reg_id}" if old_reg_id else "") }' - values = ( - reg_id, - True if 'contact_notifications_{}'.format(str_end) in form else False, - _clean_value(form['contact_type_{}'.format(str_end)]), - _clean_value(form['contact_name_{}'.format(str_end)]), - re.sub("[^0-9]", "", form['contact_phone_{}'.format(str_end)]), - _clean_email(form['contact_email_{}'.format(str_end)]) - ) - else: - str_end = f'_{iteration}_{reg_id}' if from_update_reg else (f"_{iteration}_{old_reg_id}" if old_reg_id else "") - values = ( - reg_id, - True if f'contact_notifications{str_end}' in form else False, - _clean_value(form[f'contact_type{str_end}']), - _clean_value(form[f'contact_name{str_end}']), - re.sub("[^0-9]", "", form[f'contact_phone{str_end}']), - _clean_email(form[f'contact_email{str_end}']) - ) + #if iteration > 1: + #if not _acceptable_contact(form, iteration, reg_id if from_update_reg else (old_reg_id if old_reg_id else None)): + # return + #str_end = f'{iteration}{ f"_{reg_id}" if from_update_reg else (f"_{old_reg_id}" if old_reg_id else "") }' + values = ( + reg_id, + contact['contact_notifications'], + _clean_value(contact['contact_type']), + _clean_value(contact['contact_name']), + re.sub("[^0-9]", "", contact['contact_phone']), + _clean_email(contact['contact_email']) + ) operation = """INSERT INTO registration_contacts( registration_id, @@ -610,26 +653,24 @@ def create_registration_contact(form, reg_id, iteration, from_update_reg=None, o conn.close() -def update_registration_contact(form, reg_id, iteration, no_contacts): +def update_registration_contact(contact, reg_id): cur = None conn = None values = () try: - if not _acceptable_contact(form, iteration, reg_id): - if iteration <= no_contacts: # contact is not in form but was in original contact list -> need to delete - return delete_registration_contact(reg_id, form[f'cont_id_{iteration}']) - return - if iteration > no_contacts: # contact is in form but not in original list -> need to create - return create_registration_contact(form, reg_id, iteration, from_update_reg=True) - str_end = f'{iteration}_{reg_id}' + # if contact_id is not there or is less than 0, then + # it is a new contact. + if 'contact_id' not in contact or contact['contact_id'] < 0: + return create_registration_contact(contact, reg_id) + values = ( - True if 'contact_notifications_{}'.format(str_end) in form else False, - _clean_value(form['contact_type_{}'.format(str_end)]), - _clean_value(form['contact_name_{}'.format(str_end)]), - re.sub("[^0-9]", "", form['contact_phone_{}'.format(str_end)]), - _clean_email(form['contact_email_{}'.format(str_end)]), - reg_id, - form[f'cont_id_{iteration}'] + contact['contact_notifications'], + _clean_value(contact['contact_type']), + _clean_value(contact['contact_name']), + re.sub("[^0-9]", "", contact['contact_phone']), + _clean_email(contact['contact_email']), + _set_int(reg_id), + _set_int(contact['contact_id']) ) conn = psycopg.connect( host=APCD_DB['host'], @@ -725,14 +766,14 @@ def create_other_exception(form, sub_data): ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) """ values = ( - form["business-name"], + form["otherExceptionBusinessName"], sub_data[1], sub_data[2], sub_data[3], - _clean_value(form['requestor-name']), - _clean_email(form['requestor-email']), + _clean_value(form['requestorName']), + _clean_email(form['requestorEmail']), "Other", - _clean_date(form['expiration-date']), + _clean_date(form['expirationDateOther']), _clean_value(form['justification']), "Pending" ) @@ -751,7 +792,7 @@ def create_other_exception(form, sub_data): conn.close() -def create_threshold_exception(form, iteration, sub_data): +def create_threshold_exception(form, exception, sub_data): cur = None conn = None values = () @@ -782,20 +823,20 @@ def create_threshold_exception(form, iteration, sub_data): ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) """ values = ( - _clean_value(form['business-name_{}'.format(iteration)]), + _clean_value(int(exception['businessName'])), sub_data[1], sub_data[2], sub_data[3], - _clean_value(form['requestor-name']), - _clean_email(form['requestor-email']), - "threshold", - _clean_date(form['expiration-date_{}'.format(iteration)]), - _clean_value(form['file_type_{}'.format(iteration)]), - _clean_value(form['field-threshold-exception_{}'.format(iteration)]), - _clean_value(form['threshold-requested_{}'.format(iteration)]), + _clean_value(form['requestorName']), + _clean_email(form['requestorEmail']), + _clean_value(form['exceptionType']), + _clean_date(exception['expiration_date']), + _clean_value(exception['fileType']), + _clean_value(exception['fieldCode']), + _clean_value(exception['requested_threshold']), _clean_value(form['justification']), "pending", - _clean_value((form['required_threshold_{}'.format(iteration)])), + _clean_value((exception['required_threshold'])) ) cur = conn.cursor() cur.execute(operation, values) @@ -849,6 +890,40 @@ def get_cdl_exceptions(file_type): conn.close() +def get_user_submission_log(log_id, log_type, user=None): + cur = None + conn = None + try: + conn = db_connect() + log_column_name = 'html_log' if log_type == 'html' else 'json_log' + filename_column_name = 'html_path' if log_type == 'html' else 'json_path' + + query = f""" + SELECT {log_column_name}, {filename_column_name} + FROM submission_logs + JOIN submissions ON submissions.submission_id = submission_logs.submission_id + JOIN submitter_users ON submissions.submitter_id = submitter_users.submitter_id + WHERE submission_logs.log_id = %s AND {log_column_name} IS NOT NULL + """ + + params = [log_id] + # for submitter scenario + if user is not None: + query += " AND submitter_users.user_id = %s" + params.append(user) + + query += " LIMIT 1" + + cur = conn.cursor() + cur.execute(query, params) + return cur.fetchall() + finally: + if cur is not None: + cur.close() + if conn is not None: + conn.close() + + def get_user_submissions_and_logs(user): cur = None conn = None @@ -865,18 +940,29 @@ def get_user_submissions_and_logs(user): SELECT json_build_object( 'submission_id', submissions.submission_id, 'submitter_id', submissions.submitter_id, + 'entity_name', submitters.entity_name, 'file_name', submissions.zip_file_name, 'status', submissions.status, 'outcome', submissions.outcome, 'received_timestamp', submissions.received_timestamp, 'updated_at', submissions.updated_at, + 'payor_code', submissions.payor_code, 'view_modal_content', ( SELECT COALESCE(json_agg(json_build_object( 'log_id', submission_logs.log_id, 'submission_id', submission_logs.submission_id, + 'entity_name', submitters.entity_name, 'file_type', submission_logs.file_type, 'validation_suite', submission_logs.validation_suite, 'outcome', submission_logs.outcome, + 'has_json_log', CASE + WHEN submission_logs.json_log IS NOT NULL THEN 1 + ELSE 0 + END, + 'has_html_log', CASE + WHEN submission_logs.html_log IS NOT NULL THEN 1 + ELSE 0 + END, 'file_type_name', ( SELECT standard_codes.item_value FROM standard_codes WHERE UPPER(submission_logs.file_type) = UPPER(standard_codes.item_code) AND list_name='submission_file_type' @@ -888,11 +974,13 @@ def get_user_submissions_and_logs(user): FROM submissions LEFT JOIN submission_logs ON submissions.submission_id = submission_logs.submission_id + LEFT JOIN submitters + ON submitters.submitter_id = submissions.submitter_id WHERE submissions.submitter_id IN ( SELECT submitter_users.submitter_id FROM submitter_users WHERE submitter_users.user_id = %s ) - GROUP BY (submissions.submission_id) + GROUP BY (submissions.submission_id, submitters.entity_name) ORDER BY submissions.received_timestamp DESC """ cur = conn.cursor() @@ -928,18 +1016,32 @@ def get_all_submissions_and_logs(): 'received_timestamp', submissions.received_timestamp, 'updated_at', submissions.updated_at, 'view_modal_content', ( - SELECT COALESCE(json_agg(json_build_object( - 'log_id', submission_logs.log_id, - 'submission_id', submission_logs.submission_id, - 'file_type', submission_logs.file_type, - 'validation_suite', submission_logs.validation_suite, - 'outcome', submission_logs.outcome, - 'file_type_name', ( - SELECT standard_codes.item_value FROM standard_codes - WHERE UPPER(submission_logs.file_type) = UPPER(standard_codes.item_code) AND list_name='submission_file_type' - LIMIT 1 - ) - )), '[]'::json) + SELECT CASE + WHEN COUNT(submission_logs.log_id) = 0 THEN '[]'::json + ELSE json_agg(json_build_object( + 'log_id', submission_logs.log_id, + 'submission_id', submission_logs.submission_id, + 'entity_name', submitters.entity_name, + 'file_type', submission_logs.file_type, + 'validation_suite', submission_logs.validation_suite, + 'outcome', submission_logs.outcome, + 'has_json_log', CASE + WHEN submission_logs.json_log IS NOT NULL THEN 1 + ELSE 0 + END, + 'has_html_log', CASE + WHEN submission_logs.html_log IS NOT NULL THEN 1 + ELSE 1 + END, + 'file_type_name', ( + SELECT standard_codes.item_value + FROM standard_codes + WHERE UPPER(submission_logs.file_type) = UPPER(standard_codes.item_code) + AND list_name='submission_file_type' + LIMIT 1 + ) + )) + END ) ) FROM submissions @@ -960,41 +1062,25 @@ def get_all_submissions_and_logs(): if conn is not None: conn.close() -def create_extension(form, iteration, sub_data): +def create_extension(form, extension, sub_data): cur = None conn = None values = () try: - if iteration > 1: - values = ( - _clean_value(form['business-name_{}'.format(iteration)]), - _clean_date(form['requested-target-date_{}'.format(iteration)]), - _clean_value(form['extension-type_{}'.format(iteration)]), - int((form['applicable-data-period_{}'.format(iteration)].replace("-", ""))), - _clean_date(form['hidden-current-expected-date_{}'.format(iteration)]), - "pending", - _clean_value(sub_data[1]), - _clean_value(sub_data[2]), - _clean_value(sub_data[3]), - _clean_value(form["requestor-name"]), - _clean_email(form["requestor-email"]), - _clean_value(form["justification"]) - ) - else: - values = ( - _clean_value(form['business-name_{}'.format(iteration)]), - _clean_date(form['requested-target-date_{}'.format(iteration)]), - _clean_value(form['extension-type_{}'.format(iteration)]), - int((form['applicable-data-period_{}'.format(iteration)].replace("-", ""))), - _clean_date(form['hidden-current-expected-date_{}'.format(iteration)]), + values = ( + _clean_value(extension['businessName']), + _clean_value(extension['requestedTargetDate']), + _clean_value(extension['extensionType']), + _clean_value(extension['applicableDataPeriod'].replace("-", "")), + _clean_value(extension['currentExpectedDate']), "pending", _clean_value(sub_data[1]), _clean_value(sub_data[2]), _clean_value(sub_data[3]), - _clean_value(form["requestor-name"]), - _clean_email(form["requestor-email"]), + _clean_value(form["requestorName"]), + _clean_email(form["requestorEmail"]), _clean_value(form["justification"]) - ) + ) operation = """INSERT INTO extensions( submitter_id, @@ -1021,10 +1107,10 @@ def create_extension(form, iteration, sub_data): ) cur = conn.cursor() cur.execute(operation, values) - conn.commit() + conn.commit() except Exception as error: - logger.error(error) + logger.error('DB error related to extension request creation: %s', error) return error finally: @@ -1033,62 +1119,47 @@ def create_extension(form, iteration, sub_data): if conn is not None: conn.close() + def update_extension(form): cur = None conn = None try: - conn = psycopg.connect( - host=APCD_DB['host'], - dbname=APCD_DB['database'], - user=APCD_DB['user'], - password=APCD_DB['password'], - port=APCD_DB['port'], - sslmode='require' - ) - cur = conn.cursor() - operation = """UPDATE extensions - SET - updated_at= %s,""" - - set_values = [] - # to set column names for query to the correct DB name - columns = { - 'applicable-data-period': 'applicable_data_period', - 'status': 'status', - 'outcome': 'outcome', - 'approved-expiration-date': 'approved_expiration_date' - } - # To make sure fields are not blank. - # If they aren't, add column to update set operation - for field, column_name in columns.items(): - value = form.get(field) - if value not in (None, ""): - set_values.append(f"{column_name} = %s") - - # to allow notes to be cleared, need to move notes out of the loop that ignores none - operation += ", ".join(set_values) + ", notes = %s WHERE extension_id = %s" - ## add last update time to all extension updates - values = [ - datetime.now(), - ] - - for field, column_name in columns.items(): - value = form.get(field) - if value not in (None, ""): - # to make sure applicable data period field is an int to insert to DB - if column_name == 'applicable_data_period': - values.append(int(value.replace('-', ''))) - # else server side clean values - else: - values.append(_clean_value(value)) - - # to allow notes to be cleared, need to move notes out of the loop that ignores none - values.append(_clean_value(form['notes'])) - ## to make sure extension id is last in query to match with WHERE statement - values.append(_clean_value(form['extension_id'])) - - cur.execute(operation, values) - conn.commit() + with db_connect() as conn: + cur = conn.cursor() + query = "UPDATE extensions SET updated_at = %s" + values = [datetime.now()] # Timestamp for updated_at + + # Map form fields to DB columns + columns = { + 'applicable_data_period': 'applicable_data_period', + 'status': 'status', + 'outcome': 'outcome', + 'approved_expiration_date': 'approved_expiration_date' + } + + # Build the SET clause dynamically + set_clauses = [] + for field, column_name in columns.items(): + value = form.get(field) + if value not in (None, "", "None"): + set_clauses.append(f"{column_name} = %s") + if column_name == 'applicable_data_period': + values.append(int(value.replace('-', ''))) + elif column_name == 'approved_expiration_date': + # Convert to None if the value is 'None' (string) + values.append(None if value == 'None' else _clean_value(value)) + else: + values.append(_clean_value(value)) + + # Include 'notes' field, allowing it to be cleared + set_clauses.append("notes = %s") + values.append(_clean_value(form.get('notes', ""))) + + query += ", " + ", ".join(set_clauses) + " WHERE extension_id = %s" + values.append(_clean_value(form['extension_id'])) + + cur.execute(query, values) + conn.commit() except Exception as error: logger.error(error) return error @@ -1096,6 +1167,7 @@ def update_extension(form): if cur is not None: cur.close() + def get_submitter_info(user): cur = None conn = None @@ -1308,7 +1380,7 @@ def update_exception(form): # to set column names for query to the correct DB name columns = { 'approved_threshold': 'approved_threshold', - 'approved': 'approved_expiration_date', + 'approved_expiration_date': 'approved_expiration_date', 'status': 'status', 'outcome': 'outcome', } @@ -1401,5 +1473,9 @@ def _clean_date(date_string): return None def _set_int(value): - if len(value): + if value is None or value == '': + return None + try: return int(float(value)) + except (ValueError, TypeError): + raise ValueError(f"Invalid input for _set_int: expected a numeric value or empty string. Value: {value}") diff --git a/apcd_cms/src/apps/utils/registrations_data_formatting.py b/apcd_cms/src/apps/utils/registrations_data_formatting.py index 5e6435ad..7dba06d8 100644 --- a/apcd_cms/src/apps/utils/registrations_data_formatting.py +++ b/apcd_cms/src/apps/utils/registrations_data_formatting.py @@ -1,22 +1,23 @@ -def _set_registration(reg, reg_ents, reg_conts): - org_types = { - 'carrier': 'Insurance Carrier', - 'tpa_aso': 'Plan Administrator¹ (TPA/ASO)', - 'pbm': 'Pharmacy Benefit Manager (PBM)' +def _get_orgtypes(): + return { + 'carrier': 'Insurance Carrier', + 'tpa_aso': 'Plan Administrator¹ (TPA/ASO)', + 'pbm': 'Pharmacy Benefit Manager (PBM)', } + + +def _set_registration_for_listing(reg): + org_types = _get_orgtypes() return { - 'biz_name': reg[5], - 'type': org_types[reg[4]] if (reg[4] and reg[4] in org_types.keys()) else None, - 'location': '{city}, {state}'.format - ( - city=reg[7], - state=reg[8] - ), - 'reg_status': reg[3].title() if reg[3] else None, - 'reg_id': reg[0], - 'year': reg[10], - 'view_modal_content': _set_modal_content(reg, reg_ents, reg_conts, org_types) - } + 'biz_name': reg[5], + 'type': org_types[reg[4]] if (reg[4] and reg[4] in org_types.keys()) else None, + 'location': '{city}, {state}'.format(city=reg[7], state=reg[8]), + 'reg_status': reg[3].title() if reg[3] else None, + 'reg_id': reg[0], + 'year': reg[10], + } + + def _set_entities(reg_ent): return { 'claim_val': reg_ent[0], @@ -40,6 +41,8 @@ def _set_entities(reg_ent): "Dental": reg_ent[16] } } + + def _set_contacts(reg_cont): def format_phone_number(num): @@ -65,16 +68,21 @@ def format_phone_number(num): 'phone': format_phone_number(reg_cont[5]) if reg_cont[5] else None, 'email': reg_cont[6], } -def _set_modal_content(reg, reg_ent, reg_cont, org_types): + + +def _set_registration(reg, reg_ent, reg_cont): + org_types = _get_orgtypes() return { + 'reg_id': reg[0], 'biz_name': reg[5], 'type': org_types[reg[4]] if (reg[4] and reg[4] in org_types.keys()) else None, 'city': reg[7], 'state': reg[8], 'address': reg[6], - 'zip': reg[9], + 'zip': reg[9].strip(), 'for_self': reg[2], 'year': reg[10], + 'status': reg[3].title() if reg[3] else None, 'entities': [_set_entities(ent) for ent in reg_ent], 'contacts': [_set_contacts(cont) for cont in reg_cont], 'org_types': org_types, diff --git a/apcd_cms/src/apps/view_submitter_users/__init__.py b/apcd_cms/src/apps/view_submitter_users/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apcd_cms/src/apps/view_submitter_users/apps.py b/apcd_cms/src/apps/view_submitter_users/apps.py new file mode 100644 index 00000000..c2fedd25 --- /dev/null +++ b/apcd_cms/src/apps/view_submitter_users/apps.py @@ -0,0 +1,4 @@ +from django.apps import AppConfig + +class ViewSubmitterUsersConfig(AppConfig): + name = 'apps.view_submitter_users' diff --git a/apcd_cms/src/apps/view_submitter_users/templates/view_submitter_users.html b/apcd_cms/src/apps/view_submitter_users/templates/view_submitter_users.html new file mode 100644 index 00000000..43f03163 --- /dev/null +++ b/apcd_cms/src/apps/view_submitter_users/templates/view_submitter_users.html @@ -0,0 +1,12 @@ +{% extends "apcd_cms/templates/standard.html" %} +{% load static %} + +{% block content %} + + +
+ {% include "nav_cms_breadcrumbs.html" %} +
+
+ +{%endblock %} diff --git a/apcd_cms/src/apps/view_submitter_users/urls.py b/apcd_cms/src/apps/view_submitter_users/urls.py new file mode 100644 index 00000000..3a293c7f --- /dev/null +++ b/apcd_cms/src/apps/view_submitter_users/urls.py @@ -0,0 +1,12 @@ +from django.urls import path +from django.views.generic import TemplateView +from apps.view_submitter_users.views import ViewSubmitterUsersTable, UpdateSubmitterUserView + +app_name = 'administration' +urlpatterns = [ + path('view-submitter-users/', TemplateView.as_view(template_name='view_submitter_users.html'), name='view_submitter_users'), + path('view-submitter-users/api/', ViewSubmitterUsersTable.as_view(), name='view_submitter_users_api'), + path('view-submitter-users/api/options', ViewSubmitterUsersTable.as_view(), name='view_submitter_users_api_options'), + path('view-submitter-users/api/modal//', ViewSubmitterUsersTable.as_view(), name='view_submitter_users_modal'), + path('submitter-users//', UpdateSubmitterUserView.as_view(), name='update_submitter_user'), +] diff --git a/apcd_cms/src/apps/view_submitter_users/views.py b/apcd_cms/src/apps/view_submitter_users/views.py new file mode 100644 index 00000000..2c2e6e05 --- /dev/null +++ b/apcd_cms/src/apps/view_submitter_users/views.py @@ -0,0 +1,195 @@ +from django.core.paginator import Paginator +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse +from django.views.generic.base import TemplateView +from django.views import View +from django.template import loader +from apps.utils.apcd_database import get_submitter_users, update_user +from apps.utils.apcd_groups import is_apcd_admin +import logging +import json + +# Logs errors for debugging & error handling? +logger = logging.getLogger(__name__) + +class ViewSubmitterUsersTable(TemplateView): + template_name = 'view_submitter_users.html' + + # Checks if the user is authenticated or an admin + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not is_apcd_admin(request.user): + return HttpResponseRedirect('/') + return super().dispatch(request, *args, **kwargs) + + # Sends the request to get the data complete with error handling + def get(self, request, *args, **kwargs): + if 'options' in request.path: + return self.get_options(request) + if 'modal' in request.path: + return self.get_modals(request, kwargs['modal_type']) + + status = request.GET.get('status', 'Active') + payor_code = request.GET.get('payor_code', 'All') + page_number = int(request.GET.get('page', 1)) + items_per_page = int(request.GET.get('limit', 50)) + + try: + user_content = get_submitter_users() + filtered_users = self.filter_submitter_users(user_content, status, payor_code) + + paginator = Paginator(filtered_users, items_per_page) + page_info = paginator.get_page(page_number) + + context = self.get_view_users_json(list(page_info)) + context['page_num'] = page_info.number + context['total_pages'] = paginator.num_pages + + return JsonResponse({'response': context}) + except Exception as e: + logger.error("Error fetching filtered user data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + # Retrieves the data with context added? + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context.update(self.get_view_users_json(get_submitter_users())) + return context + + def get_options(self, request): + try: + status_options = ['All', 'Active', 'Inactive'] + user_content = get_submitter_users() + user_list = sorted(list(set(user[11] if user[11] else 'None' for user in user_content))) + org_options = ['All'] + user_list + return JsonResponse({ + 'status_options': status_options, + 'org_options': org_options, + }) + except Exception as e: + logger.error("Error fetching options data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + # Retrieves both the View and Edit modals for getting/changing data + def get_modals(self, request, modal_type): + if modal_type == 'view': + modal_template = 'view_submitter_users_modal.html' + elif modal_type == 'edit': + modal_template = 'edit_submitter_users_modal.html' + else: + return JsonResponse({'error': 'Invalid modal type'}, status=400) + + modal_content = loader.render_to_string(modal_template) + return JsonResponse({'content': modal_content}) + + # Post requests to update user information? + def post(self, request): + form = request.POST.copy() + + def _err_msg(resp): + if hasattr(resp, 'pgerror'): + return resp.pgerror + if isinstance(resp, Exception): + return str(resp) + return None + + def _edit_user(form): + errors = [] + user_response = update_user(form) + if _err_msg(user_response): + errors.append(_err_msg(user_response)) + if len(errors) != 0: + logger.debug(print(errors)) + template = loader.get_template('view_user_edit_error.html') + else: + logger.debug(print("success")) + template = loader.get_template('view_user_edit_success.html') + return template + + template = _edit_user(form) + return HttpResponse(template.render({}, request)) + + # Filters users based on status and organization + def filter_submitter_users(self, users, status, payor_code): + def _set_submitter_user(usr): + return { + 'submitter_id': usr[0], + 'user_id': usr[1], + 'user_name': usr[2], + 'entity_name': usr[3] if usr[3] else 'None', + 'role_name': usr[4], + 'status': 'Active' if usr[5] else 'Inactive', + 'user_number': usr[6], + 'payor_code': usr[7], + 'role_id': usr[8], + 'user_email': usr[9], + 'notes': usr[10], + 'org_name': usr[11], + } + + user_list = [_set_submitter_user(user) for user in users] + + if status != 'All': + user_list = [user for user in user_list if user['status'] == status] + + if payor_code != 'All': + user_list = [user for user in user_list if user['org_name'] == payor_code] + + return user_list + + # Retrieves a JSON object containing all users + def get_view_users_json(self, user_content): + context = { + 'page': [], + 'pagination_url_namespaces': 'administration:view_users' + } + + def _set_user(usr): + return { + 'submitter_id': usr['submitter_id'], + 'user_id': usr['user_id'], + 'user_name': usr['user_name'], + 'entity_name': usr['entity_name'], + 'role_name': usr['role_name'], + 'status': usr['status'], + 'user_number': usr['user_number'], + # Show payor_code as org_name + 'payor_code': usr['org_name'], + 'role_id': usr['role_id'], + 'user_email': usr['user_email'], + 'notes': usr['notes'], + 'org_name': usr['org_name'], + 'view_link': f"/administration/view-user-details/{usr['user_id']}", + 'edit_link': f"/administration/edit-user/{usr['user_id']}", + } + + for user in user_content: + context['page'].append(_set_user(user)) + + return context + +class UpdateSubmitterUserView(View): + # Checks if the user is authenticated or an admin + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not is_apcd_admin(request.user): + return HttpResponseRedirect('/') + return super().dispatch(request, *args, **kwargs) + + # Error handling + def _err_msg(self, resp): + if hasattr(resp, 'pgerror'): + return resp.pgerror + if isinstance(resp, Exception): + return str(resp) + return None + + # Updates the table with user changes + def put(self, request, user_number): + data = json.loads(request.body) + errors = [] + user_response = update_user(data) + if self._err_msg(user_response): + errors.append(self._err_msg(user_response)) + if len(errors) != 0: + logger.debug(print(errors)) + return JsonResponse({'message': 'Cannot edit user'}, status=500) + + return JsonResponse({'message': 'User updated successfully'}) diff --git a/apcd_cms/src/apps/view_users/static/view_users_table/css/table.css b/apcd_cms/src/apps/view_users/static/view_users_table/css/table.css index d18b5dbb..7d19ac20 100644 --- a/apcd_cms/src/apps/view_users/static/view_users_table/css/table.css +++ b/apcd_cms/src/apps/view_users/static/view_users_table/css/table.css @@ -2,15 +2,20 @@ table-layout: inherit; } +.status-filter.org-filter { + width: max-content; + padding-right: 20px; +} + /* SEE: https://css-tricks.com/responsive-data-tables/ */ @media (max-width: 767px) { /* To label the cells */ /* RFE: Add `data-label` to each cell so we can use `attr(data-label)` */ - .users-table td:nth-of-type(1):before { content: "User Name"; } - .users-table td:nth-of-type(2):before { content: "Role"; } - .users-table td:nth-of-type(3):before { content: "Organization"; } - .users-table td:nth-of-type(4):before { content: "Email"; } - .users-table td:nth-of-type(5):before { content: "Created"; } - .users-table td:nth-of-type(6):before { content: "Updated"; } - .users-table td:nth-of-type(7):before { content: "Notes"; } + .users-table td:nth-of-type(1):before { content: "User Id"; } + .users-table td:nth-of-type(2):before { content: "Name"; } + .users-table td:nth-of-type(3):before { content: "Entity Organization'"; } + .users-table td:nth-of-type(4):before { content: "Role"; } + .users-table td:nth-of-type(5):before { content: "Status"; } + .users-table td:nth-of-type(6):before { content: "User Number"; } + .users-table td:nth-of-type(7):before { content: "Actions"; } } diff --git a/apcd_cms/src/apps/view_users/templates/view_users.html b/apcd_cms/src/apps/view_users/templates/view_users.html index b94c1e73..a2be3eba 100644 --- a/apcd_cms/src/apps/view_users/templates/view_users.html +++ b/apcd_cms/src/apps/view_users/templates/view_users.html @@ -1,4 +1,4 @@ -{% extends "standard.html" %} +{% extends "apcd_cms/templates/standard.html" %} {% load static %} {% block content %} @@ -9,123 +9,7 @@
{% include "nav_cms_breadcrumbs.html" %} - -

View Users

-
-

View submitted users.

-
-
-
- Filter by Status: - - Filter by Organization: - - {% if selected_status != 'All' or selected_org != 'All' %} - - {% endif %} -
-
- -
- - - {% for k in header %} - - {% endfor %} - - - - - {% for r in page %} - - - - - - - - - - {% endfor %} - -
{{k}}active
{{r.user_id}}{{r.user_name}}{{r.entity_name}}{{r.role_name}}{{r.status}}{{r.user_number}}
- {% include 'paginator.html' %} +
- -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/apcd_cms/src/apps/view_users/urls.py b/apcd_cms/src/apps/view_users/urls.py index f3d6b196..4f45d55d 100644 --- a/apcd_cms/src/apps/view_users/urls.py +++ b/apcd_cms/src/apps/view_users/urls.py @@ -1,8 +1,12 @@ from django.urls import path -from apps.view_users.views import ViewUsersTable +from django.views.generic import TemplateView +from apps.view_users.views import ViewUsersTable, UpdateUserView, UpdateUserView app_name = 'administration' urlpatterns = [ - path('view-users/', ViewUsersTable.as_view(), name='view_users'), - path('view-users//', ViewUsersTable.as_view()) + path('view-users/', TemplateView.as_view(template_name='view_users.html'), name='view_users'), + path('view-users/api/', ViewUsersTable.as_view(), name='view_users_api'), + path('view-users/api/options', ViewUsersTable.as_view(), name='view_users_api_options'), + path('view-users/api/modal//', ViewUsersTable.as_view(), name='view_users_modal'), + path('users//', UpdateUserView.as_view(), name='update_user'), ] diff --git a/apcd_cms/src/apps/view_users/views.py b/apcd_cms/src/apps/view_users/views.py index 67b96cea..9ed5c855 100644 --- a/apcd_cms/src/apps/view_users/views.py +++ b/apcd_cms/src/apps/view_users/views.py @@ -1,29 +1,90 @@ -from django.http import HttpResponseRedirect, HttpResponse, JsonResponse -from django.core.paginator import Paginator, EmptyPage +from django.core.paginator import Paginator +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.views.generic.base import TemplateView +from django.views import View from django.template import loader from apps.utils.apcd_database import get_users, update_user from apps.utils.apcd_groups import is_apcd_admin -from apps.utils.utils import table_filter -from apps.components.paginator.paginator import paginator import logging +import json logger = logging.getLogger(__name__) class ViewUsersTable(TemplateView): template_name = 'view_users.html' - ##FORM FUNCTION - def post(self, request): + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not is_apcd_admin(request.user): + return HttpResponseRedirect('/') + return super().dispatch(request, *args, **kwargs) - form = request.POST.copy() + def get(self, request, *args, **kwargs): + if 'options' in request.path: + return self.get_options(request) + if 'modal' in request.path: + return self.get_modals(request, kwargs['modal_type']) + status = request.GET.get('status', 'Active') + org = request.GET.get('org', 'All') + page_number = int(request.GET.get('page', 1)) + items_per_page = int(request.GET.get('limit', 50)) + + try: + user_content = get_users() + filtered_users = self.filter_users(user_content, status, org) + + paginator = Paginator(filtered_users, items_per_page) + page_info = paginator.get_page(page_number) + + context = self.get_view_users_json(list(page_info), selected_status=status, selected_org=org) + context['page_num'] = page_info.number + context['total_pages'] = paginator.num_pages + + return JsonResponse({'response': context}) + except Exception as e: + logger.error("Error fetching filtered user data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context.update(self.get_view_users_json(get_users())) + return context + + def get_options(self, request): + try: + status_options = ['All', 'Active', 'Inactive'] + user_content = get_users() + user_list = sorted(list(set(user[4] if user[4] else 'None' for user in user_content))) + org_options = ['All'] + user_list + return JsonResponse({ + 'status_options': status_options, + 'org_options': org_options + }) + except Exception as e: + logger.error("Error fetching options data: %s", e) + return JsonResponse({'error': str(e)}, status=500) + + def get_modals(self, request, modal_type): + if modal_type == 'view': + modal_template = 'view_users_modal.html' + elif modal_type == 'edit': + modal_template = 'edit_users_modal.html' + else: + return JsonResponse({'error': 'Invalid modal type'}, status=400) + + modal_content = loader.render_to_string(modal_template) + return JsonResponse({'content': modal_content}) + + def post(self, request): + form = request.POST.copy() + def _err_msg(resp): if hasattr(resp, 'pgerror'): return resp.pgerror if isinstance(resp, Exception): return str(resp) return None - + def _edit_user(form): errors = [] user_response = update_user(form) @@ -36,94 +97,90 @@ def _edit_user(form): logger.debug(print("success")) template = loader.get_template('view_user_edit_success.html') return template - + template = _edit_user(form) return HttpResponse(template.render({}, request)) - def get(self, request, *args, **kwargs): - user_content = get_users() - - - context = self.get_context_data(user_content, *args,**kwargs) - template = loader.get_template(self.template_name) - return HttpResponse(template.render(context, request)) - ##END FORM FUNCTION - - user_content = get_users() - - def dispatch(self, request, *args, **kwargs): - if not request.user.is_authenticated or not is_apcd_admin(request.user): - return HttpResponseRedirect('/') - return super(ViewUsersTable, self).dispatch(request, *args, **kwargs) - - def get_context_data(self, user_content=user_content, *args, **kwargs): - context = super(ViewUsersTable, self).get_context_data(*args, **kwargs) + + def filter_users(self, users, status, org): + def _set_user(usr): + return { + 'role_id': usr[0], + 'user_id': usr[1], + 'user_email': usr[2], + 'user_name': usr[3], + 'entity_name': usr[4] if usr[4] else 'None', + 'created_at': usr[5], + 'updated_at': usr[6], + 'notes': usr[7], + 'status': 'Active' if usr[8] else 'Inactive', + 'user_number': usr[9], + 'role_name': usr[10], + 'entity_name_no_parens': usr[4].replace("(", "").replace(")", "") if usr[4] else "None", # just for filtering purposes + } + + user_list = [_set_user(user) for user in users] + + if status != 'All': + user_list = [user for user in user_list if user['status'] == status] + + if org != 'All': + org_no_parens = org.replace("(", "").replace(")", "") + user_list = [user for user in user_list if user['entity_name_no_parens'] == org_no_parens] + + return user_list + + def get_view_users_json(self, user_content, selected_status='All', selected_org='All'): + context = { + 'page': [], + 'selected_status': selected_status, + 'selected_org': selected_org, + 'pagination_url_namespaces': 'administration:view_users' + } def _set_user(usr): return { - 'role_id': usr[0], - 'user_id': usr[1], - 'user_email': usr[2], - 'user_name': usr[3], - 'entity_name': usr[4] if usr[4] else 'None', - 'created_at': usr[5], - 'updated_at': usr[6], - 'notes': usr[7], - 'status': 'Active' if usr[8] else 'Inactive', - 'user_number': usr[9], - 'role_name': usr[10], - 'entity_name_no_parens': usr[4].replace("(", "").replace(")", "") if usr[4] else "None", # just for filtering purposes - 'active': usr[8], - } - - context['header'] = ['User ID', 'Name', 'Entity Organization', 'Role', 'Status', 'User Number', 'See More'] - context['status_options'] = ['All', 'Active', 'Inactive'] - context['filter_options'] = ['All', 'None'] - context['role_options'] = ['SUBMITTER_USER', 'SUBMITTER_ADMIN','APCD_ADMIN'] - - context['status'] = ['Active', 'Inactive'] - - # this kind of sucks, we should make this not hard coded, just getting it to work for now - context['roles'] = [ - {'role_id': 1, 'role_name': 'APCD_ADMIN'}, - {'role_id': 2, 'role_name': 'SUBMITTER_ADMIN'}, - {'role_id': 3, 'role_name': 'SUBMITTER_USER'} - ] - - try: - page_num = int(self.request.GET.get('page')) - except: - page_num = 1 - table_entries = [] + 'user_id': usr['user_id'], + 'user_name': usr['user_name'], + 'entity_name': usr['entity_name'], + 'role_name': usr['role_name'], + 'status': usr['status'], + 'user_number': usr['user_number'], + 'user_email': usr['user_email'], + 'notes': usr['notes'], + 'created_at': usr['created_at'], + 'updated_at': usr['updated_at'], + 'view_link': f"/administration/view-user-details/{usr['user_id']}", + 'edit_link': f"/administration/edit-user/{usr['user_id']}", + } + for user in user_content: - table_entries.append(_set_user(user,)) - org_name = user[4] if user[4] else None - if org_name not in context['filter_options']: # prevent duplicates - context['filter_options'].append(user[4]) - context['filter_options'] = sorted(context['filter_options'],key=lambda x: (x != 'All', x is None, x if x is not None else '')) - - queryStr = '' - status_filter = self.request.GET.get('status') - org_filter = self.request.GET.get('org') - role_filter = self.request.GET.get('role_name') - - context['selected_status'] = 'All' - if status_filter is not None and status_filter !='All': - context['selected_status'] = status_filter - queryStr += f'&status={status_filter}' - table_entries = table_filter(status_filter, table_entries, 'status', False) - - if role_filter is not None and role_filter !='All': - context['selected_role'] = role_filter - table_entries = table_filter(role_filter, table_entries, 'role_name', False) - - context['selected_org'] = 'All' - if org_filter is not None and org_filter != 'All': - context['selected_org'] = org_filter - queryStr += f'&org={org_filter}' - table_entries = table_filter(org_filter.replace("(", "").replace(")",""), table_entries, 'entity_name_no_parens') - - context['query_str'] = queryStr - context.update(paginator(self.request, table_entries)) - context['pagination_url_namespaces'] = 'administration:view_users' + context['page'].append(_set_user(user)) return context + + +class UpdateUserView(View): + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not is_apcd_admin(request.user): + return HttpResponseRedirect('/') + return super().dispatch(request, *args, **kwargs) + + def _err_msg(self, resp): + if hasattr(resp, 'pgerror'): + return resp.pgerror + if isinstance(resp, Exception): + return str(resp) + return None + + def put(self, request, user_number): + data = json.loads(request.body) + errors = [] + user_response = update_user(data) + if self._err_msg(user_response): + errors.append(self._err_msg(user_response)) + if len(errors) != 0: + logger.debug(print(errors)) + return JsonResponse({'message': 'Cannot edit user'}, status=500) + + return JsonResponse({'message': 'User updated successfully'}) diff --git a/apcd_cms/src/client/.eslintrc b/apcd_cms/src/client/.eslintrc new file mode 100644 index 00000000..439b023b --- /dev/null +++ b/apcd_cms/src/client/.eslintrc @@ -0,0 +1,23 @@ +{ + "parser": "@typescript-eslint/parser", + "extends": [ + "plugin:react/recommended", + "plugin:jsx-a11y/recommended", + "plugin:react-hooks/recommended" + ], + "env": { + "browser": true, + "node": true + }, + "settings": { + "react": { "version": "detect" } + }, + "rules": { + "react/jsx-key": 0, + "jsx-a11y/anchor-is-valid": 0, + "react-hooks/exhaustive-deps": 0, + "react-hooks/rules-of-hooks": 0, + "react/display-name": 0, + "react/prop-types": 0 + } + } \ No newline at end of file diff --git a/apcd_cms/src/client/.gitignore b/apcd_cms/src/client/.gitignore new file mode 100644 index 00000000..4d29575d --- /dev/null +++ b/apcd_cms/src/client/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/apcd_cms/src/client/.prettierrc b/apcd_cms/src/client/.prettierrc new file mode 100644 index 00000000..dc2fb828 --- /dev/null +++ b/apcd_cms/src/client/.prettierrc @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} \ No newline at end of file diff --git a/apcd_cms/src/client/README.md b/apcd_cms/src/client/README.md new file mode 100644 index 00000000..b87cb004 --- /dev/null +++ b/apcd_cms/src/client/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/apcd_cms/src/client/babel.config.js b/apcd_cms/src/client/babel.config.js new file mode 100644 index 00000000..dbb3aa5c --- /dev/null +++ b/apcd_cms/src/client/babel.config.js @@ -0,0 +1,11 @@ +module.exports = { + presets: [ + [ + "@babel/preset-react", + { + runtime: "automatic", + development: true + } + ] + ], + }; \ No newline at end of file diff --git a/apcd_cms/src/client/build_client.sh b/apcd_cms/src/client/build_client.sh new file mode 100644 index 00000000..9dc57e25 --- /dev/null +++ b/apcd_cms/src/client/build_client.sh @@ -0,0 +1,3 @@ +#!/bin/bash -x +cd /code/client +npm ci && npm run build \ No newline at end of file diff --git a/apcd_cms/src/client/package-lock.json b/apcd_cms/src/client/package-lock.json new file mode 100644 index 00000000..89c284f8 --- /dev/null +++ b/apcd_cms/src/client/package-lock.json @@ -0,0 +1,18151 @@ +{ + "name": "apcd-components", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "apcd-components", + "version": "0.1.0", + "dependencies": { + "@tanstack/react-query": "^4.24.4", + "@types/axios": "^0.14.0", + "@types/reactstrap": "^8.7.2", + "formik": "^2.4.6", + "js-cookie": "^2.2.1", + "react": "^17.0.2", + "react-copy-to-clipboard": "^5.0.2", + "react-dom": "^17.0.2", + "react-query": "^3.34.15", + "react-router-dom": "^6.23.1", + "react-table": "^7.8.0", + "reactstrap": "^9.2.2", + "typescript": "^4.4.3", + "yup": "^1.4.0" + }, + "devDependencies": { + "@babel/cli": "^7.15.4", + "@babel/core": "^7.7.5", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/preset-env": "^7.7.6", + "@babel/preset-react": "^7.7.4", + "@rollup/plugin-eslint": "^8.0.1", + "@tacc/core-styles": "^2.37.0", + "@testing-library/jest-dom": "^5.0.2", + "@testing-library/react": "^12.1.1", + "@types/js-cookie": "^3.0.6", + "@types/react": "^17.0.26", + "@types/react-dom": "^17.0.9", + "@types/react-redux": "^7.1.18", + "@types/react-table": "^7.7.12", + "@typescript-eslint/parser": "^5.1.0", + "@vitejs/plugin-react": "^1.0.1", + "babel-eslint": "^10.0.3", + "babel-jest": "^27.3.0", + "babel-preset-react-app": "^9.1.2", + "eslint": "^7.32.0", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", + "jest": "^27.3.0", + "prettier": "^2.4.1", + "react-test-renderer": "^17.0.2", + "redux-mock-store": "^1.5.3", + "redux-saga-test-plan": "^4.0.0-rc.3", + "sass": "^1.42.1", + "stylelint": "^14.4.0", + "stylelint-config-recommended": "^7.0.0", + "stylelint-config-standard": "^25.0.0", + "typescript": "^4.4.3", + "vite": "^5.4.11", + "weak-key": "^1.0.1" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/cli": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.23.9.tgz", + "integrity": "sha512-vB1UXmGDNEhcf1jNAHKT9IlYk1R+hehVTLFlCLHBi8gfuHQGP6uRjgXVYU0EVlI/qwAWpstqkBdf2aez3/z/5Q==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "commander": "^4.0.1", + "convert-source-map": "^2.0.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.2.0", + "make-dir": "^2.1.0", + "slash": "^2.0.0" + }, + "bin": { + "babel": "bin/babel.js", + "babel-external-helpers": "bin/babel-external-helpers.js" + }, + "engines": { + "node": ">=6.9.0" + }, + "optionalDependencies": { + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", + "chokidar": "^3.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/cli/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", + "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", + "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-decorators": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.23.3.tgz", + "integrity": "sha512-cf7Niq4/+/juY67E0PbgH0TDhLQ5J7zS8C/Q5FFx+DWyrRa9sUQdTXkjqKu8zGvuqr7vw1muKiukseihU+PJDA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.23.3.tgz", + "integrity": "sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz", + "integrity": "sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-flow": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", + "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", + "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", + "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", + "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", + "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-transform-react-display-name": "^7.23.3", + "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz", + "integrity": "sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-typescript": "^7.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz", + "integrity": "sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.0.4.tgz", + "integrity": "sha512-8/iCd8lH10gKNsq5detnbGWiFd6PXK2wB8wjE6fHNNhtqvshyMrIJgffwRcw6yl/gzGTH+N1i+KRhjqHxqYTmg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.5.tgz", + "integrity": "sha512-4Wo8raj9YF3PnZ5iGrAl+BSsk2MYBOEUS/X4k1HL9mInhyCVftEG02MywdvelXlwZGUF2XTQ0qj9Jd398mhqrw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz", + "integrity": "sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.5.tgz", + "integrity": "sha512-6dHr2NDsBMiZCPkGDi2qMfIbzV2kWV8Dh7SVb1FZGnN/r2TI4TSAkVF8rCG5L70yQZHMcQGB84yp8Zm+RGhoHA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.5.tgz", + "integrity": "sha512-jgq0oGbit7TxWYP8y2hWWfV64xzcAgJk54PBYZ2fDrRgEDy1l5YMCrFawnn+5JETh/E1jjXPDFhFEYhwr3vA3g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz", + "integrity": "sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-design-tokens": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-design-tokens/-/postcss-design-tokens-4.0.4.tgz", + "integrity": "sha512-GjM+YcX7JRt9BSjDoxMjuZ8dBeI9Ol77a+cEWnq62K+b19SYlAWNgwJgrRfYmgm+9gAsAt+/dEy5O8qI7wT0PA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.4.tgz", + "integrity": "sha512-xmzFCGTkkLDs7q9vVaRGlnu8s51lRRJzHsaJ/nXmkQuyg0q7gh7rTbJ0bY5sSVet+KB7MTIxRXRUCl2tm7RODA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-calc": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.5.tgz", + "integrity": "sha512-VQDayRhC/Mg1fuo8/4F43La5aROgvVyqtCqdNyGvRKi6L1+zXfwQ583nImi7k/gn2GNJH82Bf9mutTuT1GtXzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.5.tgz", + "integrity": "sha512-l3ShDdAt/szbyBh3Jz27MRFt5WPAbnVCMsU7Vs7EbBxJQNgVDrcu1APBB2nPagDJOyhI6/IahuW7nb6grWVTpA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.5.tgz", + "integrity": "sha512-bPn/SQyiiYjWkwK2ykc7O9LliMR50YfUGukd6jQI2okHzB7NxNt/IS45tS1Muk7Hhf3B9Lbmg1Ofq36tBmM92Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz", + "integrity": "sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-initial": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz", + "integrity": "sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz", + "integrity": "sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz", + "integrity": "sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz", + "integrity": "sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.4.tgz", + "integrity": "sha512-zgdBOCI9aKoy5GK9tb/3ve0pl7vH0HJg7rfQEWT3TZiIKh7XEWucDSTSwnwgdgtgz50UxrOfbK+C59M+u2fE2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/css-calc": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz", + "integrity": "sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz", + "integrity": "sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.5.tgz", + "integrity": "sha512-19bsJQFyJNSEhpaVq0Mq1E0HDXfx8qMHa/bR1MaHr1UD4DWvM2/J6YXb9OVGS7eFl92Y3c84Yggn9uFv13vsiQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz", + "integrity": "sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.5.tgz", + "integrity": "sha512-5VrE4hAwv/ZpuL1Yo0ZGGFi1QPpIikp/rzz7LnpQ31ACQVRIA5/M9qZmJbRlZVsJ4bUFSQ3dq6kHSHrCt2uM6Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.4.tgz", + "integrity": "sha512-JjShuWZkmIOT8EfI7lYjl7V5qM29LNDdnnSo5O7v/InJJHfeiQjtxyAaZzKGXzpkghPrCAcgLfJ+IyqTdXo7IA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-calc": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz", + "integrity": "sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.4.tgz", + "integrity": "sha512-nn+gWTZZlSnwbyUtGQCnvBXIx1TX+HVStvIm3221dWGQvp47bB5giMBbuAK4a/UJGBbfDQhGKEbYq++WWM1i1A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-calc": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/fake-timers/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/fake-timers/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/fake-timers/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/fake-timers/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/globals/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/globals/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/globals/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/globals/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/globals/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/globals/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", + "dev": true, + "optional": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@redux-saga/core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.3.0.tgz", + "integrity": "sha512-L+i+qIGuyWn7CIg7k1MteHGfttKPmxwZR5E7OsGikCL2LzYA0RERlaUY00Y3P3ZV2EYgrsYlBrGs6cJP5OKKqA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/runtime": "^7.6.3", + "@redux-saga/deferred": "^1.2.1", + "@redux-saga/delay-p": "^1.2.1", + "@redux-saga/is": "^1.1.3", + "@redux-saga/symbols": "^1.1.3", + "@redux-saga/types": "^1.2.1", + "typescript-tuple": "^2.2.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/redux-saga" + } + }, + "node_modules/@redux-saga/deferred": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz", + "integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g==", + "dev": true, + "peer": true + }, + "node_modules/@redux-saga/delay-p": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz", + "integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==", + "dev": true, + "peer": true, + "dependencies": { + "@redux-saga/symbols": "^1.1.3" + } + }, + "node_modules/@redux-saga/is": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz", + "integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==", + "dev": true, + "peer": true, + "dependencies": { + "@redux-saga/symbols": "^1.1.3", + "@redux-saga/types": "^1.2.1" + } + }, + "node_modules/@redux-saga/symbols": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz", + "integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg==", + "dev": true, + "peer": true + }, + "node_modules/@redux-saga/types": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz", + "integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA==", + "dev": true, + "peer": true + }, + "node_modules/@remix-run/router": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", + "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/plugin-eslint": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-eslint/-/plugin-eslint-8.0.5.tgz", + "integrity": "sha512-cSasMRxV4lddMpjcHSN9QV4MCDxYQWuXhc3xa0lUuw+DEQuS0tNoKNZEzsEZqoEvs4KVkHgDpbhQ4jKU+AZ9iw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^4.0.0", + "eslint": "^7.12.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tacc/core-styles": { + "version": "2.37.2", + "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.37.2.tgz", + "integrity": "sha512-Mj47VU6WBUrkaT48OWHgKBPeWgUS1vkKuGupXmUjH4SjeKj1nXAAXdCUP5WpVfKccsyWmESyprMuCOlVqIDEQA==", + "dev": true, + "license": "MIT", + "bin": { + "core-styles": "src/cli.js" + }, + "engines": { + "node": ">=15.x", + "npm": ">=7.x" + }, + "peerDependencies": { + "@csstools/postcss-design-tokens": "^4.0.1", + "commander": "^9.4.1", + "cssnano": "^5.1.15", + "js-yaml": "^4.1.0", + "merge-lite": "^1.0.2", + "node-cmd": "^5.0.0", + "postcss": "^8.4.38", + "postcss-banner": "^4.0.1", + "postcss-cli": "^10.0.0", + "postcss-extend": "^1.0.5", + "postcss-import": "^15.0.0", + "postcss-mixins": "^10.0.1", + "postcss-preset-env": "^10.0.2", + "postcss-replace": "^2.0.1" + } + }, + "node_modules/@tanstack/query-core": { + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz", + "integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.36.1.tgz", + "integrity": "sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==", + "dependencies": { + "@tanstack/query-core": "4.36.1", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@testing-library/dom": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", + "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@testing-library/dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", + "integrity": "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=8", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@testing-library/jest-dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", + "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.0.0", + "@types/react-dom": "<18.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "<18.0.0", + "react-dom": "<18.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true + }, + "node_modules/@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==", + "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "dependencies": { + "axios": "*" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", + "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + }, + "node_modules/@types/react": { + "version": "17.0.75", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.75.tgz", + "integrity": "sha512-MSA+NzEzXnQKrqpO63CYqNstFjsESgvJAdAyyJ1n6ZQq/GLgf6nOfIKwk+Twuz0L1N6xPe+qz5xRCJrbhMaLsw==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "17.0.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.25.tgz", + "integrity": "sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==", + "dev": true, + "dependencies": { + "@types/react": "^17" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.33", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz", + "integrity": "sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==", + "dev": true, + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-table": { + "version": "7.7.19", + "resolved": "https://registry.npmjs.org/@types/react-table/-/react-table-7.7.19.tgz", + "integrity": "sha512-47jMa1Pai7ily6BXJCW33IL5ghqmCWs2VM9s+h1D4mCaK5P4uNkZOW3RMMg8MCXBvAJ0v9+sPqKjhid0PaJPQA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/reactstrap": { + "version": "8.7.2", + "resolved": "https://registry.npmjs.org/@types/reactstrap/-/reactstrap-8.7.2.tgz", + "integrity": "sha512-8sYGS/LhG+ic8vhLwxhuVn+TSqS1lKzplm9BHv4JaQoetStAi9uOqP2VREfefIRT3JnOq5Y+G7Afdryvn+UgZQ==", + "deprecated": "This is a stub types definition. reactstrap provides its own type definitions, so you do not need this installed.", + "dependencies": { + "reactstrap": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/testing-library__jest-dom": { + "version": "5.14.9", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", + "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", + "dev": true, + "dependencies": { + "@types/jest": "*" + } + }, + "node_modules/@types/yargs": { + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.9.tgz", + "integrity": "sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz", + "integrity": "sha512-aurBNmMo0kz1O4qRoY+FM4epSA39y3ShWGuqfLRA/3z0oEJAdtoSfgA3aO98/PCCHAqMaduLxIxErWrVKIFzXA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.17.10", + "@babel/plugin-transform-react-jsx": "^7.17.3", + "@babel/plugin-transform-react-jsx-development": "^7.16.7", + "@babel/plugin-transform-react-jsx-self": "^7.16.7", + "@babel/plugin-transform-react-jsx-source": "^7.16.7", + "@rollup/pluginutils": "^4.2.1", + "react-refresh": "^0.13.0", + "resolve": "^1.22.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", + "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, + "node_modules/babel-eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", + "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.5.0", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", + "dev": true + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-react-app": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz", + "integrity": "sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA==", + "dev": true, + "dependencies": { + "@babel/core": "7.9.0", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-proposal-decorators": "7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3", + "@babel/plugin-proposal-numeric-separator": "7.8.3", + "@babel/plugin-proposal-optional-chaining": "7.9.0", + "@babel/plugin-transform-flow-strip-types": "7.9.0", + "@babel/plugin-transform-react-display-name": "7.8.3", + "@babel/plugin-transform-runtime": "7.9.0", + "@babel/preset-env": "7.9.0", + "@babel/preset-react": "7.9.1", + "@babel/preset-typescript": "7.9.0", + "@babel/runtime": "7.9.0", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz", + "integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/preset-env": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", + "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.0", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.0", + "browserslist": "^4.9.1", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/preset-modules": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/preset-react": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.1.tgz", + "integrity": "sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-react-display-name": "^7.8.3", + "@babel/plugin-transform-react-jsx": "^7.9.1", + "@babel/plugin-transform-react-jsx-development": "^7.9.0", + "@babel/plugin-transform-react-jsx-self": "^7.9.0", + "@babel/plugin-transform-react-jsx-source": "^7.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-preset-react-app/node_modules/@babel/runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.0.tgz", + "integrity": "sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/babel-preset-react-app/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/babel-preset-react-app/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "node_modules/babel-preset-react-app/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/babel-preset-react-app/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "peer": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/broadcast-channel": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz", + "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "detect-node": "^2.1.0", + "js-sha3": "0.8.0", + "microseconds": "0.2.0", + "nano-time": "1.0.0", + "oblivious-set": "1.0.0", + "rimraf": "3.0.2", + "unload": "2.2.0" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001677", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", + "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/core-js-compat": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", + "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-functions-list": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.1.tgz", + "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==", + "dev": true, + "engines": { + "node": ">=12 || >=16" + } + }, + "node_modules/css-has-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.1.tgz", + "integrity": "sha512-EOcoyJt+OsuKfCADgLT7gADZI5jMzIe/AeI6MeAYKiFBDmNmM7kk46DtSfMj5AohUJisqVzopBpnQTlvbyaBWg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", + "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "peer": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "peer": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssdb": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.1.2.tgz", + "integrity": "sha512-ba3HmHU/lxy9nfz/fQLA/Ul+/oSdSOXqoR53BDmRvXTfRbkGqHKqr2rSxADYMRF4uD8vZhMlCQ6c5TEfLLkkVA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ], + "license": "MIT-0", + "peer": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "peer": true, + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "peer": true, + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "peer": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "peer": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "peer": true + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "peer": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "peer": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.52", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.52.tgz", + "integrity": "sha512-xtoijJTZ+qeucLBDNztDOuQBE1ksqjvNjvqFoST3nGC7fSpqJ+X6BdTBaY5BHG+IhWWmpc6b/KfpeuEDupEPOQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", + "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.7", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.2", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.1", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.0", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.1", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz", + "integrity": "sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==", + "dev": true, + "dependencies": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.4", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.2", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/expect/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/expect/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/expect/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/expect/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formik": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz", + "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==", + "funding": [ + { + "type": "individual", + "url": "https://opencollective.com/formik" + } + ], + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.1", + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/formik/node_modules/deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/formik/node_modules/react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fsm-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fsm-iterator/-/fsm-iterator-1.1.0.tgz", + "integrity": "sha512-hg47CNYdIGJ5m9WSKh617LHRdvJo4PiF0VkncFLwPVxKvBEQfSPd1qx/xLV/eSusewEu0C8eUFrsLsWlBgIcOg==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/globby/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", + "dev": true + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "dev": true, + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-config/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-jasmine2/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "dev": true, + "peer": true + }, + "node_modules/js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/known-css-properties": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", + "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", + "dev": true + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "dependencies": { + "leven": "^3.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "peer": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/match-sorter": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz", + "integrity": "sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "remove-accents": "0.5.0" + } + }, + "node_modules/mathml-tag-names": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", + "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true, + "peer": true + }, + "node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-lite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/merge-lite/-/merge-lite-1.0.2.tgz", + "integrity": "sha512-28Q9aFRLzLCSp/2MLV49sbilBcCw7pIxq9YfOuX8+g/cMbPgYcAZgI0BLHnsb7ZRgvYOuaEGQPYJk8OWcGHk4A==", + "dev": true, + "peer": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/microseconds": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz", + "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nano-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz", + "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==", + "dependencies": { + "big-integer": "^1.6.16" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-cmd": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-cmd/-/node-cmd-5.0.0.tgz", + "integrity": "sha512-4sQTJmsS5uZKAPz/Df9fnIbmvOySfGdW+UreH4X5NcAOOpKjaE+K5wf4ehNBbZVPo0vQ36RkRnhhsXXJAT+Syw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "peer": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-path": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", + "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oblivious-set": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz", + "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", + "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-banner": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-banner/-/postcss-banner-4.0.1.tgz", + "integrity": "sha512-vpxkcADfBp28r50HH3HPVBoQxE2u0IF5WG9qTQMdYJWqk7VsFBWPAnVkDMGZwvBiJFU7B9HYos6o/fz++PVTgQ==", + "dev": true, + "peer": true, + "dependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-cli": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-10.1.0.tgz", + "integrity": "sha512-Zu7PLORkE9YwNdvOeOVKPmWghprOtjFQU3srMUGbdz3pHJiFh7yZ4geiZFMkjMfB0mtTFR3h8RemR62rPkbOPA==", + "dev": true, + "peer": true, + "dependencies": { + "chokidar": "^3.3.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^11.0.0", + "get-stdin": "^9.0.0", + "globby": "^13.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^4.0.0", + "postcss-reporter": "^7.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "slash": "^5.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "postcss": "index.js" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/postcss-cli/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "peer": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/postcss-cli/node_modules/globby/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/postcss-cli/node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/postcss-cli/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/postcss-cli/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "peer": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/postcss-cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.5.tgz", + "integrity": "sha512-zW97tq5t2sSSSZQcIS4y6NDZj79zVv8hrBIJ4PSFZFmMBcjYqCt8sRXFGIYZohCpfFHmimMNqJje2Qd3qqMNdg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", + "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", + "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-custom-media": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz", + "integrity": "sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz", + "integrity": "sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz", + "integrity": "sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", + "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz", + "integrity": "sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-extend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-extend/-/postcss-extend-1.0.5.tgz", + "integrity": "sha512-zplAc8IovPMe/JqV0B9nl6o6sElIX7VX1CP2FbV+lGZud3hcnDMr4clN0S8xdHthQoTNDN2K1Q+z0YEW5FWc8A==", + "dev": true, + "peer": true, + "dependencies": { + "postcss": "^5.0.4" + } + }, + "node_modules/postcss-extend/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-extend/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-extend/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-extend/node_modules/chalk/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/postcss-extend/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-extend/node_modules/postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/postcss-extend/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-extend/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-extend/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/postcss-focus-visible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", + "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-focus-within": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", + "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", + "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", + "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "peer": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-lab-function": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.5.tgz", + "integrity": "sha512-q2M8CfQbjHxbwv1GPAny05EVuj0WByUgq/OWKgpfbTHnMchtUqsVQgaW1mztjSZ4UPufwuTLB14fmFGsoTE/VQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/css-color-parser": "^3.0.5", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-logical": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.0.0.tgz", + "integrity": "sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "peer": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-mixins": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-mixins/-/postcss-mixins-10.0.1.tgz", + "integrity": "sha512-5+cI9r8L5ChegVsLM9pXa53Ft03Mt9xAq+kvzqfrUHGPCArVGOfUvmQK2CLP3XWWP2dqxDLQI+lIcXG+GTqOBQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "fast-glob": "^3.3.2", + "postcss-js": "^4.0.1", + "postcss-simple-vars": "^7.0.1", + "sugarss": "^4.0.1" + }, + "engines": { + "node": "^18.0 || >= 20.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "peer": true, + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", + "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "peer": true, + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", + "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", + "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.0.9.tgz", + "integrity": "sha512-mpfJWMAW6szov+ifW9HpNUUZE3BoXoHc4CDzNQHdH2I4CwsqulQ3bpFNUR6zh4tg0BUcqM7UUAbzG4UTel8QYw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/postcss-cascade-layers": "^5.0.1", + "@csstools/postcss-color-function": "^4.0.5", + "@csstools/postcss-color-mix-function": "^3.0.5", + "@csstools/postcss-content-alt-text": "^2.0.4", + "@csstools/postcss-exponential-functions": "^2.0.4", + "@csstools/postcss-font-format-keywords": "^4.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.5", + "@csstools/postcss-gradients-interpolation-method": "^5.0.5", + "@csstools/postcss-hwb-function": "^4.0.5", + "@csstools/postcss-ic-unit": "^4.0.0", + "@csstools/postcss-initial": "^2.0.0", + "@csstools/postcss-is-pseudo-class": "^5.0.1", + "@csstools/postcss-light-dark-function": "^2.0.7", + "@csstools/postcss-logical-float-and-clear": "^3.0.0", + "@csstools/postcss-logical-overflow": "^2.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", + "@csstools/postcss-logical-resize": "^3.0.0", + "@csstools/postcss-logical-viewport-units": "^3.0.3", + "@csstools/postcss-media-minmax": "^2.0.4", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.4", + "@csstools/postcss-nested-calc": "^4.0.0", + "@csstools/postcss-normalize-display-values": "^4.0.0", + "@csstools/postcss-oklab-function": "^4.0.5", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-relative-color-syntax": "^3.0.5", + "@csstools/postcss-scope-pseudo-class": "^4.0.1", + "@csstools/postcss-stepped-value-functions": "^4.0.4", + "@csstools/postcss-text-decoration-shorthand": "^4.0.1", + "@csstools/postcss-trigonometric-functions": "^4.0.4", + "@csstools/postcss-unset-value": "^4.0.0", + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.1", + "css-blank-pseudo": "^7.0.1", + "css-has-pseudo": "^7.0.1", + "css-prefers-color-scheme": "^10.0.0", + "cssdb": "^8.1.2", + "postcss-attribute-case-insensitive": "^7.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^7.0.5", + "postcss-color-hex-alpha": "^10.0.0", + "postcss-color-rebeccapurple": "^10.0.0", + "postcss-custom-media": "^11.0.5", + "postcss-custom-properties": "^14.0.4", + "postcss-custom-selectors": "^8.0.4", + "postcss-dir-pseudo-class": "^9.0.1", + "postcss-double-position-gradients": "^6.0.0", + "postcss-focus-visible": "^10.0.1", + "postcss-focus-within": "^9.0.1", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^6.0.0", + "postcss-image-set-function": "^7.0.0", + "postcss-lab-function": "^7.0.5", + "postcss-logical": "^8.0.0", + "postcss-nesting": "^13.0.1", + "postcss-opacity-percentage": "^3.0.0", + "postcss-overflow-shorthand": "^6.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^10.0.0", + "postcss-pseudo-class-any-link": "^10.0.1", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env/node_modules/@csstools/selector-resolve-nested": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz", + "integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-preset-env/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-preset-env/node_modules/postcss-nesting": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz", + "integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/selector-resolve-nested": "^3.0.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", + "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-replace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-replace/-/postcss-replace-2.0.1.tgz", + "integrity": "sha512-T83GVovCkBQkFCTmuid0B2bWNu/O0Bh/HDMeEGFC62EwMvVBLZQFYM7iBbcGT48QDXSNSX6e/X1Q7/Syh5NFng==", + "dev": true, + "peer": true, + "dependencies": { + "kind-of": "^6.0.3", + "object-path": "^0.11.8" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-reporter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.1.0.tgz", + "integrity": "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "picocolors": "^1.0.0", + "thenby": "^1.3.4" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-resolve-nested-selector": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", + "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==", + "dev": true + }, + "node_modules/postcss-safe-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "dev": true, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", + "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-simple-vars": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz", + "integrity": "sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.1" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "peer": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-copy-to-clipboard": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", + "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", + "dependencies": { + "copy-to-clipboard": "^3.3.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^15.3.0 || 16 || 17 || 18" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/react-query": { + "version": "3.39.3", + "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz", + "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "broadcast-channel": "^3.4.1", + "match-sorter": "^6.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.13.0.tgz", + "integrity": "sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", + "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", + "dependencies": { + "@remix-run/router": "1.16.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", + "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", + "dependencies": { + "@remix-run/router": "1.16.1", + "react-router": "6.23.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-table": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", + "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17.0.0-0 || ^18.0.0" + } + }, + "node_modules/react-test-renderer": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", + "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.1", + "react-is": "^17.0.2", + "react-shallow-renderer": "^16.13.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-test-renderer/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/reactstrap": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz", + "integrity": "sha512-4KroiGOdqZLAnMGzHjpErW3G7bLB+QbKzzMLIDXydPIV0y74lpdL7WtXHkLWAGInd97WCPNx4+R0NQDPyzIfhw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@popperjs/core": "^2.6.0", + "classnames": "^2.2.3", + "prop-types": "^15.5.8", + "react-popper": "^2.2.4", + "react-transition-group": "^4.4.2" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "peer": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-mock-store": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz", + "integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==", + "dev": true, + "dependencies": { + "lodash.isplainobject": "^4.0.6" + } + }, + "node_modules/redux-saga": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.3.0.tgz", + "integrity": "sha512-J9RvCeAZXSTAibFY0kGw6Iy4EdyDNW7k6Q+liwX+bsck7QVsU78zz8vpBRweEfANxnnlG/xGGeOvf6r8UXzNJQ==", + "dev": true, + "peer": true, + "dependencies": { + "@redux-saga/core": "^1.3.0" + } + }, + "node_modules/redux-saga-test-plan": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/redux-saga-test-plan/-/redux-saga-test-plan-4.0.6.tgz", + "integrity": "sha512-ESdbFoDWCeJ/EiFdUNSCGtA2CC9tnuvHDm6k06gVFa98EIeR2hpzFkGk9kJ1/hpMUnYFp+OOEEITIrZeDYBfFg==", + "dev": true, + "dependencies": { + "fsm-iterator": "^1.1.0", + "lodash.isequal": "^4.5.0", + "lodash.ismatch": "^4.4.0" + }, + "peerDependencies": { + "@redux-saga/is": "^1.0.1", + "@redux-saga/symbols": "^1.0.1", + "redux-saga": "^1.0.1" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", + "integrity": "sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.0.0", + "get-intrinsic": "^1.2.3", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sass": { + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", + "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true, + "peer": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-search": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", + "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", + "dev": true + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/stylelint": { + "version": "14.16.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.1.tgz", + "integrity": "sha512-ErlzR/T3hhbV+a925/gbfc3f3Fep9/bnspMiJPorfGEmcBbXdS+oo6LrVtoUZ/w9fqD6o6k7PtUlCOsCRdjX/A==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "balanced-match": "^2.0.0", + "colord": "^2.9.3", + "cosmiconfig": "^7.1.0", + "css-functions-list": "^3.1.0", + "debug": "^4.3.4", + "fast-glob": "^3.2.12", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^6.0.1", + "global-modules": "^2.0.0", + "globby": "^11.1.0", + "globjoin": "^0.1.4", + "html-tags": "^3.2.0", + "ignore": "^5.2.1", + "import-lazy": "^4.0.0", + "imurmurhash": "^0.1.4", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.26.0", + "mathml-tag-names": "^2.1.3", + "meow": "^9.0.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.19", + "postcss-media-query-parser": "^0.2.3", + "postcss-resolve-nested-selector": "^0.1.1", + "postcss-safe-parser": "^6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "resolve-from": "^5.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "style-search": "^0.1.0", + "supports-hyperlinks": "^2.3.0", + "svg-tags": "^1.0.0", + "table": "^6.8.1", + "v8-compile-cache": "^2.3.0", + "write-file-atomic": "^4.0.2" + }, + "bin": { + "stylelint": "bin/stylelint.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz", + "integrity": "sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==", + "dev": true, + "peerDependencies": { + "stylelint": "^14.4.0" + } + }, + "node_modules/stylelint-config-standard": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-25.0.0.tgz", + "integrity": "sha512-21HnP3VSpaT1wFjFvv9VjvOGDtAviv47uTp3uFmzcN+3Lt+RYRv6oAplLaV51Kf792JSxJ6svCJh/G18E9VnCA==", + "dev": true, + "dependencies": { + "stylelint-config-recommended": "^7.0.0" + }, + "peerDependencies": { + "stylelint": "^14.4.0" + } + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true + }, + "node_modules/stylelint/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stylelint/node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/stylelint/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/sugarss": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-4.0.1.tgz", + "integrity": "sha512-WCjS5NfuVJjkQzK10s8WOBY+hhDxxNt/N6ZaGwxFZ+wN3/lKKFSaaKUNecULcTTvE4urLcKaZFQD8vO0mOZujw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "peer": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenby": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", + "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", + "dev": true, + "peer": true + }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", + "dev": true + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz", + "integrity": "sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typescript-compare": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", + "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==", + "dev": true, + "peer": true, + "dependencies": { + "typescript-logic": "^0.0.0" + } + }, + "node_modules/typescript-logic": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", + "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==", + "dev": true, + "peer": true + }, + "node_modules/typescript-tuple": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", + "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", + "dev": true, + "peer": true, + "dependencies": { + "typescript-compare": "^0.0.2" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unload": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz", + "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==", + "dependencies": { + "@babel/runtime": "^7.6.2", + "detect-node": "^2.0.4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/rollup": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/weak-key": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/weak-key/-/weak-key-1.0.3.tgz", + "integrity": "sha512-+rUqNjaFsPhwrPdfmrHhKxbufsSUojAbX26PBawFWRHmKn01V1z6GWiizkpbXt225MxrvFm/ULYVxdFpkdY3cQ==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", + "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.5", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yup": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", + "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/apcd_cms/src/client/package.json b/apcd_cms/src/client/package.json new file mode 100644 index 00000000..addc6405 --- /dev/null +++ b/apcd_cms/src/client/package.json @@ -0,0 +1,86 @@ +{ + "name": "apcd-components", + "type": "module", + "version": "0.1.0", + "private": true, + "dependencies": { + "@tanstack/react-query": "^4.24.4", + "@types/axios": "^0.14.0", + "@types/reactstrap": "^8.7.2", + "formik": "^2.4.6", + "js-cookie": "^2.2.1", + "react": "^17.0.2", + "react-copy-to-clipboard": "^5.0.2", + "react-dom": "^17.0.2", + "react-query": "^3.34.15", + "react-router-dom": "^6.23.1", + "react-table": "^7.8.0", + "reactstrap": "^9.2.2", + "typescript": "^4.4.3", + "yup": "^1.4.0" + }, + "scripts": { + "lint": "npm run lint:js && npm run lint:css && npm run prettier:check", + "lint:js": "eslint . --ext .js,.jsx,.ts,.tsx", + "lint:css": "stylelint '**/*.{css,scss,sass}'", + "prettier:check": "prettier --check src", + "prettier:fix": "prettier --write src", + "build": "vite build", + "test": "TZ=America/Chicago jest", + "test:watch": "npm run test -- --watch", + "staging": "vite preview", + "dev": "vite" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@babel/cli": "^7.15.4", + "@babel/core": "^7.7.5", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/preset-env": "^7.7.6", + "@babel/preset-react": "^7.7.4", + "@rollup/plugin-eslint": "^8.0.1", + "@tacc/core-styles": "^2.37.0", + "@testing-library/jest-dom": "^5.0.2", + "@testing-library/react": "^12.1.1", + "@types/js-cookie": "^3.0.6", + "@types/react": "^17.0.26", + "@types/react-dom": "^17.0.9", + "@types/react-redux": "^7.1.18", + "@types/react-table": "^7.7.12", + "@typescript-eslint/parser": "^5.1.0", + "@vitejs/plugin-react": "^1.0.1", + "babel-eslint": "^10.0.3", + "babel-jest": "^27.3.0", + "babel-preset-react-app": "^9.1.2", + "eslint": "^7.32.0", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-react": "^7.26.1", + "eslint-plugin-react-hooks": "^4.2.0", + "jest": "^27.3.0", + "prettier": "^2.4.1", + "react-test-renderer": "^17.0.2", + "redux-mock-store": "^1.5.3", + "redux-saga-test-plan": "^4.0.0-rc.3", + "sass": "^1.42.1", + "stylelint": "^14.4.0", + "stylelint-config-recommended": "^7.0.0", + "stylelint-config-standard": "^25.0.0", + "typescript": "^4.4.3", + "vite": "^5.4.11", + "weak-key": "^1.0.1" + } +} diff --git a/apcd_cms/src/client/react-assets.html b/apcd_cms/src/client/react-assets.html new file mode 100644 index 00000000..7a986e3d --- /dev/null +++ b/apcd_cms/src/client/react-assets.html @@ -0,0 +1 @@ + diff --git a/apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.module.css b/apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.module.css new file mode 100644 index 00000000..20ecd43d --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.module.css @@ -0,0 +1,17 @@ +.modal { + color: var(--global-color-primary--xx-dark); + padding: 20px; + .h-100 { + padding: 0 10px; + } + + .tr-header { + border-bottom-color: #c6c6c6; + } +} + +.header { + font-weight: 400 !important; + background: var(--global-color-primary--x-light); + display: flex; +} diff --git a/apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.tsx b/apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.tsx new file mode 100644 index 00000000..e48467b9 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.tsx @@ -0,0 +1,410 @@ +import React, { useState, useEffect } from 'react'; +import { Modal, ModalBody, ModalHeader, Row, Col, Alert } from 'reactstrap'; +import { Field, useFormik, FormikHelpers, FormikProvider } from 'formik'; +import { fetchUtil } from 'utils/fetchUtil'; +import * as Yup from 'yup'; +import { ExceptionRow } from 'hooks/admin'; +import { formatDate } from 'utils/dateUtil'; +import styles from './EditExceptionModal.module.css'; +import QueryWrapper from 'core-wrappers/QueryWrapper'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; +import Button from 'core-components/Button'; + +interface EditRecordModalProps { + isOpen: boolean; + onClose: () => void; + exception: ExceptionRow | null; + statusOptions: string[] | undefined; + outcomeOptions: string[] | undefined; + onEditSuccess?: (updatedException: ExceptionRow) => void; +} + +interface FormValues { + exception_id: string; + approved_threshold: string; + approved_expiration_date: string; + status: string; + outcome: string; + notes: string; +} + +const EditExceptionModal: React.FC = ({ + isOpen, + onClose, + exception, + statusOptions, + outcomeOptions, + onEditSuccess, +}) => { + const [showSuccessMessage, setShowSuccessMessage] = useState(false); + const [showErrorMessage, setShowErrorMessage] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + const [isLoading, setIsLoading] = useState(true); + const [loadingError, setLoadingError] = useState( + Error('Exception data is not avalible') + ); + const dateFormat: Intl.DateTimeFormatOptions = { + year: 'numeric', + month: 'short', + day: 'numeric', + }; + + if (!exception) return null; + if (isLoading) { + setIsLoading(false); + setLoadingError(null); + } + + // Use the custom hook to get form fields and validation + const useFormFields = () => { + const initialValues: FormValues = { + ...exception, + notes: exception?.notes || 'None', // Set notes to 'None' if it is null + }; + + const validationSchema = Yup.object({ + notes: Yup.string() + .max(2000, 'Notes cannot exceed 2000 characters') + .nullable(), + }); + + return { initialValues, validationSchema }; + }; + const { initialValues, validationSchema } = useFormFields(); + let { + created_at, + entity_name, + requestor_name, + requestor_email, + request_type, + status, + outcome, + data_file_name, + field_number, + required_threshold, + requested_expiration_date, + explanation_justification, + updated_at, + } = exception.view_modal_content; + const [currentException, setCurrentException] = useState([ + { + label: 'Created', + value: created_at ? formatDate(created_at) : 'None', + }, + { + label: 'Entity Organization', + value: entity_name, + }, + { + label: 'Requestor', + value: requestor_name, + }, + { + label: 'Requestor Email', + value: requestor_email, + }, + { + label: 'Exception Type', + value: request_type, + }, + { + label: 'Status', + value: status, + }, + { + label: 'Outcome', + value: outcome ? outcome : 'None', + }, + { + label: 'File Type', + value: data_file_name ? data_file_name : 'None', + }, + { + label: 'Field Number', + value: field_number ? field_number : 'None', + }, + { + label: 'Required Threshold', + value: required_threshold ? required_threshold : 'None', + }, + { + label: 'Requested Expiration Date', + value: + (requested_expiration_date && + new Date(requested_expiration_date).toLocaleDateString( + undefined, + dateFormat + )) || + 'None', + }, + { + label: 'Explanation Justification', + value: explanation_justification || 'None', + }, + { + label: 'Last Updated', + value: updated_at ? formatDate(updated_at) : 'None', + }, + ]); + + const onSubmit = async ( + values: FormValues, + actions: FormikHelpers + ) => { + const { exception_id } = values; + const url = `administration/exceptions/${exception_id}/`; + try { + setShowSuccessMessage(false); + const response = await fetchUtil({ + url, + method: 'PUT', + body: values, + }); + setCurrentException( + currentException.map((field, index) => { + if (field.label === 'Status') { + return { + label: field.label, + value: values.status, + }; + } + if (field.label === 'Outcome') { + return { + label: field.label, + value: values.outcome, + }; + } + return field; + }) + ); + if (response) { + setShowSuccessMessage(true); + + if (onEditSuccess) onEditSuccess(response); + } + } catch (error: any) { + console.error('Error saving data:', error); + console.log(url); + if (error.response && error.response.data) { + // Use error message from the server response + setErrorMessage( + error.response.data.message || + 'An error occurred while saving the data. Please try again.' + ); + } else { + // Use generic error message + setErrorMessage( + 'An error occurred while saving the data. Please try again.' + ); + } + setShowErrorMessage(true); + } finally { + actions.setSubmitting(false); + } + }; + + const formik = useFormik({ + initialValues, + validationSchema, + onSubmit, + enableReinitialize: true, + }); + + const dismissMessages = () => { + setShowSuccessMessage(false); + setShowErrorMessage(false); + }; + + const closeBtn = ( + + ); + + return ( + <> + + + Edit Exception ID {exception.exception_id} for {exception.entity_name} + + +

Edit Selected Exception

+ + + +
+ + {exception.request_type == 'Threshold' && ( + + + + + Requested: {exception.requested_threshold}% + + + + )} + + + + + Requested Expy Date:{' '} + {exception.view_modal_content.requested_expiration_date + ? new Date( + exception.view_modal_content.requested_expiration_date + ).toLocaleDateString() + : 'None'} + + + + + + + {statusOptions?.map( + (val, index) => + val !== 'All' && ( + + ) + )} + + + + + + + {outcomeOptions?.map((val, index) => ( + + ))} + + + + + + + + 2000 character limit + + + + +
+ + Success: The exception data has been successfully updated. + + + Error: {errorMessage} + + +
+
+
+

Current Exception Information

+
+ {currentException.map((field, index) => ( + + {field.label}: + {field.value} + + ))} +
+
+
+
+ + ); +}; + +export default EditExceptionModal; diff --git a/apcd_cms/src/client/src/components/Admin/EditExceptionModal/index.ts b/apcd_cms/src/client/src/components/Admin/EditExceptionModal/index.ts new file mode 100644 index 00000000..15b11ab3 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/EditExceptionModal/index.ts @@ -0,0 +1,3 @@ +import EditExceptionModal from './EditExceptionModal'; + +export { EditExceptionModal }; diff --git a/apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.module.css b/apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.module.css new file mode 100644 index 00000000..624f460b --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.module.css @@ -0,0 +1,7 @@ +.paginatorContainer { + display: flex; + justify-content: center; /* Centers the child horizontally */ + align-items: center; /* Centers the child vertically */ + height: 100%; /* Adjust as needed */ + padding-top: 20px; +} diff --git a/apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.tsx b/apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.tsx new file mode 100644 index 00000000..e76ff4d8 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.tsx @@ -0,0 +1,181 @@ +import React, { useState, useEffect } from 'react'; +import { useExceptions, ExceptionRow } from 'hooks/admin'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import Paginator from 'core-components/Paginator'; +import ViewExceptionModal from '../ViewExceptionModal/ViewExceptionModal'; +import EditExceptionModal from '../EditExceptionModal/EditExceptionModal'; +import styles from './AdminExceptions.module.css'; +import { formatDate } from 'utils/dateUtil'; +import { ClearOptionsButton } from 'apcd-components/ClearOptionsButton'; + +export const AdminExceptions: React.FC = () => { + const [status, setStatus] = useState('Pending'); + const [org, setOrg] = useState('All'); + const [page, setPage] = useState(1); + const { data, isLoading, isError, refetch } = useExceptions( + status, + org, + page + ); + const [isViewModalOpen, setIsViewModalOpen] = useState(false); + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + const [dropdownValue, setDropdownValue] = useState(''); + + const [selectedException, setSelectedException] = + useState(null); + + useEffect(() => { + refetch(); + }, [page, refetch]); + + useEffect(() => { + setPage(1); + }, [status, org]); + + const clearSelections = () => { + setStatus('Pending'); + setOrg('All'); + setPage(1); + }; + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (isError) { + return
Error loading data
; + } + + const openAction = ( + event: React.ChangeEvent, + exception: ExceptionRow + ) => { + const selectedOption = event.target.value; + setSelectedException(exception); + setDropdownValue(''); + if (selectedOption == 'viewException') { + setIsViewModalOpen(true); + } else if (selectedOption == 'editException') { + setIsEditModalOpen(true); + } + }; + + const closeAction = () => { + refetch(); + setIsViewModalOpen(false); + setIsEditModalOpen(false); + }; + + return ( +
+
+
+ {/* Filter */} +
+ + Filter by Status: + + + + {/* Filter by Organization */} + + Filter by Organization: + + + {status !== 'Pending' || org !== 'All' ? ( + + ) : null} +
+
+
+ + + + {data?.header.map((columnName: string, index: number) => ( + + ))} + + + + {data?.page && data.page.length > 0 ? ( + data?.page.map((row: ExceptionRow, rowIndex: number) => ( + + + + + + + + + + )) + ) : ( + + + + )} + +
{columnName}
{formatDate(row.created_at)}{row.entity_name}{row.requestor_name}{row.request_type}{row.outcome}{row.status} + +
+ No Data available +
+
+ +
+ {selectedException && ( + <> + closeAction()} + /> + closeAction()} + /> + + )} +
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Admin/Exceptions/index.ts b/apcd_cms/src/client/src/components/Admin/Exceptions/index.ts new file mode 100644 index 00000000..d132434e --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Exceptions/index.ts @@ -0,0 +1,4 @@ +// index.ts +import { AdminExceptions } from './AdminExceptions'; + +export { AdminExceptions }; diff --git a/apcd_cms/src/client/src/components/Admin/Extensions/AdminExtensions.tsx b/apcd_cms/src/client/src/components/Admin/Extensions/AdminExtensions.tsx new file mode 100644 index 00000000..1b113fd0 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Extensions/AdminExtensions.tsx @@ -0,0 +1,187 @@ +import React, { useEffect, useState } from 'react'; +import { useExtensions, ExtensionRow } from 'hooks/admin'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import SectionMessage from 'core-components/SectionMessage'; +import Paginator from 'core-components/Paginator'; +import styles from './ExtensionList.module.css'; +import ViewExtensionModal from 'apcd-components/Extensions/ViewExtensionModal/ViewExtensionModal'; +import EditExtensionModal from 'apcd-components/Extensions/EditExtensionModal/EditExtensionModal'; +import { formatDate } from 'utils/dateUtil'; +import { ClearOptionsButton } from 'apcd-components/ClearOptionsButton'; + +export const AdminExtensions: React.FC = () => { + const [status, setStatus] = useState('Pending'); + const [org, setOrg] = useState('All'); + const [page, setPage] = useState(1); + const { data, isLoading, isError, refetch } = useExtensions( + status, + org, + page + ); + const [isViewModalOpen, setIsViewModalOpen] = useState(false); + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + + const [selectedExtension, setSelectedExtension] = + useState(null); + + const clearSelections = () => { + setStatus('Pending'); + setOrg(''); + setPage(1); + }; + + const closeModal = () => { + setIsViewModalOpen(false); + setIsEditModalOpen(false); + setSelectedExtension(null); + }; + + const onEditSuccess = (updatedExtension: ExtensionRow) => { + // Refresh extension data after editing is successful + refetch(); + }; + + if (isLoading) { + return ; + } + + if (isError) { + return ( + + There was an error loading the page.{''} + + Please submit a ticket. + + + ); + } + + const openAction = ( + event: React.ChangeEvent, + ext_id: string + ) => { + const actionsDropdown = event.target; + const selectedOption = actionsDropdown.value; + setSelectedExtension(data?.page.find((x) => x.ext_id === ext_id) ?? null); + if (selectedOption == 'viewExtension') { + setIsViewModalOpen(true); + } else if (selectedOption == 'editExtension') { + setIsEditModalOpen(true); + } + actionsDropdown.selectedIndex = 0; + }; + + return ( +
+

View Extension Requests

+

All submitted extension requests

+
+
+
+ {/* Filter */} + + Filter by Status: + + + + {/* Filter by Organization */} + + Filter by Organization: + + + {data?.selected_status !== 'Pending' || data?.selected_org ? ( + + ) : null} +
+
+ + + + {data?.header.map((columnName: string, index: number) => ( + + ))} + + + + {data?.page && data.page.length > 0 ? ( + data?.page.map((row: ExtensionRow, rowIndex: number) => ( + + + + + + + + + + + )) + ) : ( + + + + )} + +
{columnName}
{formatDate(row.created)}{row.org_name}{row.requestor}{row.type}{row.ext_outcome}{row.ext_status}{formatDate(row.approved_expiration_date)} + +
+ No Data available +
+
+ + {selectedExtension && ( + <> + + + + )} +
+
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Admin/Extensions/ExtensionList.module.css b/apcd_cms/src/client/src/components/Admin/Extensions/ExtensionList.module.css new file mode 100644 index 00000000..624f460b --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Extensions/ExtensionList.module.css @@ -0,0 +1,7 @@ +.paginatorContainer { + display: flex; + justify-content: center; /* Centers the child horizontally */ + align-items: center; /* Centers the child vertically */ + height: 100%; /* Adjust as needed */ + padding-top: 20px; +} diff --git a/apcd_cms/src/client/src/components/Admin/Extensions/index.ts b/apcd_cms/src/client/src/components/Admin/Extensions/index.ts new file mode 100644 index 00000000..819884ee --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Extensions/index.ts @@ -0,0 +1,4 @@ +// index.ts +import { AdminExtensions } from './AdminExtensions'; + +export { AdminExtensions }; diff --git a/apcd_cms/src/client/src/components/Admin/Registrations/AdminRegistrations.tsx b/apcd_cms/src/client/src/components/Admin/Registrations/AdminRegistrations.tsx new file mode 100644 index 00000000..4f68b66f --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Registrations/AdminRegistrations.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { RegistrationList } from 'apcd-components/Registrations/RegistrationList'; +import { useAdminRegistrations } from 'hooks/registrations'; + +export const AdminRegistrations: React.FC = () => { + return ( + + ); +}; diff --git a/apcd_cms/src/client/src/components/Admin/Registrations/index.ts b/apcd_cms/src/client/src/components/Admin/Registrations/index.ts new file mode 100644 index 00000000..284691fb --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Registrations/index.ts @@ -0,0 +1,4 @@ +// index.ts +import { AdminRegistrations } from './AdminRegistrations'; + +export { AdminRegistrations }; diff --git a/apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.module.css b/apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.module.css new file mode 100644 index 00000000..624f460b --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.module.css @@ -0,0 +1,7 @@ +.paginatorContainer { + display: flex; + justify-content: center; /* Centers the child horizontally */ + align-items: center; /* Centers the child vertically */ + height: 100%; /* Adjust as needed */ + padding-top: 20px; +} diff --git a/apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.tsx b/apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.tsx new file mode 100644 index 00000000..7514e695 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.tsx @@ -0,0 +1,186 @@ +import React, { useEffect, useState } from 'react'; +import { useSubmissions, useSubmissionFilters } from 'hooks/admin'; +import { + FileSubmissionRow, + FileSubmissionLogsModalContent, +} from 'hooks/submissions'; +import { ViewSubmissionLogsModal } from 'apcd-components/Submissions/ViewFileSubmissions'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import SectionMessage from 'core-components/SectionMessage'; +import Button from 'core-components/Button'; +import Paginator from 'core-components/Paginator'; +import styles from './AdminSubmissions.module.css'; +import { formatDate } from 'utils/dateUtil'; +import { titleCase } from 'utils/stringUtil'; +import { ClearOptionsButton } from 'apcd-components/ClearOptionsButton'; + +export const AdminSubmissions: React.FC = () => { + const header = [ + 'Received', + 'Entity Organization', + 'File Name', + 'Outcome', + 'Status', + 'Last Updated', + 'Actions', + ]; + const { + data: filterData, + isLoading: isFilterLoading, + isError: isFilterError, + } = useSubmissionFilters(); + + const [status, setStatus] = useState('In Process'); + const [sort, setSort] = useState('Newest Received'); + const [page, setPage] = useState(1); + const [viewModalOpen, setViewModalOpen] = useState(false); + const [selectedSubmission, setSelectedSubmission] = + useState(null); + + const [selectedSubmissionLog, setSelectedSubmissionLog] = useState< + FileSubmissionLogsModalContent[] + >([]); + + const closeModal = () => { + setViewModalOpen(false); + setSelectedSubmission(null); + }; + + const { + data: submissionData, + isLoading: isSubmissionsLoading, + isError: isSubmissionsError, + refetch, + } = useSubmissions(status, sort, page); + + useEffect(() => { + refetch(); + }, [status, sort, page]); + + if (isSubmissionsLoading) { + return ; + } + + if (isSubmissionsError) { + return ( + + There was an error loading the page.{' '} + + Please submit a ticket. + + + ); + } + + const clearSelections = () => { + setStatus('In Process'); + setSort('Newest Received'); + setPage(1); + }; + + return ( +
+

View File Submissions

+
+

All submissions by organizations

+
+
+
+ + Filter by Status: + + + + Sort by: + + + {status !== 'In Process' || sort !== 'Newest Received' ? ( + + ) : null} +
+
+ + + + {header.map((columnName: string, index: number) => ( + + ))} + + + + {submissionData?.page && submissionData.page.length > 0 ? ( + submissionData?.page.map( + (row: FileSubmissionRow, rowIndex: number) => ( + + + + + + + + + + ) + ) + ) : ( + + + + )} + +
{columnName}
{formatDate(row.received_timestamp)}{titleCase(row.entity_name)}{row.file_name}{titleCase(row.outcome)}{titleCase(row.status)}{formatDate(row.updated_at)} + +
+ No Data available +
+
+ +
+ {selectedSubmission && viewModalOpen && ( + + )} +
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Admin/Submissions/index.ts b/apcd_cms/src/client/src/components/Admin/Submissions/index.ts new file mode 100644 index 00000000..a05a2b4d --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/Submissions/index.ts @@ -0,0 +1,3 @@ +import { AdminSubmissions } from './AdminSubmissions'; + +export { AdminSubmissions }; diff --git a/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.module.css b/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.module.css new file mode 100644 index 00000000..a3753242 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.module.css @@ -0,0 +1,26 @@ +.modal { + color: var(--global-color-primary--xx-dark); + padding: 20px; + .h-100 { + padding: 0 10px; + } + + .tr-header { + border-bottom-color: #c6c6c6; + } +} + +.header { + font-weight: 400 !important; + background: var(--global-color-primary--x-light); + display: flex; +} + +.verticalDataList { + width: 100%; + padding-left: 40px; +} + +.verticalDataValue { + padding-left: 2.5em; +} diff --git a/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.tsx b/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.tsx new file mode 100644 index 00000000..cafec342 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.tsx @@ -0,0 +1,144 @@ +import React from 'react'; +import { Modal, ModalHeader, ModalBody, Row, Col } from 'reactstrap'; +import { ExceptionRow } from 'hooks/admin'; +import { formatModalDate } from 'utils/dateUtil'; +import styles from './ViewExceptionModal.module.css'; + +export const ViewExceptionModal: React.FC<{ + exception: ExceptionRow; + isOpen: boolean; + onClose: () => void; +}> = ({ exception, isOpen, onClose }) => { + const closeBtn = ( + + ); + + const { + created_at, + entity_name, + requestor_name, + requestor_email, + request_type, + status, + outcome, + data_file_name, + field_number, + required_threshold, + requested_threshold, + approved_threshold, + requested_expiration_date, + approved_expiration_date, + explanation_justification, + notes, + updated_at, + } = exception.view_modal_content; + const dateFormat: Intl.DateTimeFormatOptions = { + year: 'numeric', + month: 'short', + day: 'numeric', + }; + + return ( + + Exception Detail + +
+

Details

+
+ + Created + + {(created_at && formatModalDate(created_at)) || 'None'} + + + + Entity Organization + {entity_name} + + + Requestor + {requestor_name} + + + Requestor Email + {requestor_email} + + + Exception Type + {request_type} + + + Status + {status} + + + Outcome + {outcome || 'None'} + + + File Type + {data_file_name || 'None'} + + + Field Number + {field_number || 'None'} + + + Required Threshold + {required_threshold || 'None'} + + + Requested Threshold + {requested_threshold || 'None'} + + + Approved Threshold + {approved_threshold || 'None'} + + + Requested Expiration Date + + {(requested_expiration_date && + new Date(requested_expiration_date).toLocaleDateString( + undefined, + dateFormat + )) || + 'None'} + + + + Approved Expiration Date + + {(approved_expiration_date && + new Date(approved_expiration_date).toLocaleDateString( + undefined, + dateFormat + )) || + 'None'} + + + + Explanation Justification + {explanation_justification || 'None'} + + + Exception Notes + {notes || 'None'} + + + Last Updated + + {(updated_at && formatModalDate(updated_at)) || 'None'} + + +
+
+
+
+
+ ); +}; + +export default ViewExceptionModal; diff --git a/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/index.ts b/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/index.ts new file mode 100644 index 00000000..c5f3fe76 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewExceptionModal/index.ts @@ -0,0 +1,3 @@ +import { ViewExceptionModal } from './ViewExceptionModal'; + +export { ViewExceptionModal }; diff --git a/apcd_cms/src/client/src/components/Admin/ViewUsers/EditRecordModal.tsx b/apcd_cms/src/client/src/components/Admin/ViewUsers/EditRecordModal.tsx new file mode 100644 index 00000000..1dcf73df --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewUsers/EditRecordModal.tsx @@ -0,0 +1,342 @@ +import React, { useState } from 'react'; +import { + Modal, + ModalBody, + ModalHeader, + Label, + FormGroup, + Row, + Col, +} from 'reactstrap'; +import { Formik, Field, Form, ErrorMessage } from 'formik'; +import { fetchUtil } from 'utils/fetchUtil'; +import * as Yup from 'yup'; +import { UserRow } from 'hooks/admin'; +import styles from './ViewUsers.module.scss'; +import { formatDate } from 'utils/dateUtil'; +import QueryWrapper from 'core-wrappers/QueryWrapper'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; +import Button from 'core-components/Button'; + +interface EditRecordModalProps { + isOpen: boolean; + toggle: () => void; + user: UserRow | null; + onEditSuccess?: (updatedUser: UserRow) => void; +} + +const EditRecordModal: React.FC = ({ + isOpen, + toggle, + user, + onEditSuccess, +}) => { + const [successModalOpen, setSuccessModalOpen] = useState(false); + const [errorModalOpen, setErrorModalOpen] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + const [isLoading, setIsLoading] = useState(true); + const [loadingError, setLoadingError] = useState( + Error('User data is not avalible') + ); + + if (!user) return null; + console.log('The user is ', user); + if (isLoading) { + setIsLoading(false); + setLoadingError(null); + } + + const initialValues: UserRow = { + ...user, + notes: user.notes || 'None', // Set notes to 'None' if it is null + }; + + const validationSchema = Yup.object({ + user_name: Yup.string().required('Name is required'), + user_email: Yup.string() + .email('Invalid email format') + .required('Email is required'), + status: Yup.string().required('Status is required'), + role_name: Yup.string().required('Role is required'), + notes: Yup.string() + .max(2000, 'Notes cannot exceed 2000 characters') + .nullable(), + }); + + const handleSave = async ( + values: UserRow, + { setSubmitting }: { setSubmitting: (isSubmitting: boolean) => void } + ) => { + const { user_number } = values; + const url = `administration/users/${user_number}/`; + try { + const response = await fetchUtil({ + url, + method: 'PUT', + body: values, + }); + + if (onEditSuccess && response) { + onEditSuccess(response); + } + + setSuccessModalOpen(true); + } catch (error: any) { + console.error('Error saving data:', error); + console.log(url); + if (error.response && error.response.data) { + // Use error message from the server response + setErrorMessage( + error.response.data.message || + 'An error occurred while saving the data. Please try again.' + ); + } else { + // Use generic error message + setErrorMessage( + 'An error occurred while saving the data. Please try again.' + ); + } + setErrorModalOpen(true); + } finally { + setSubmitting(false); + } + }; + + const userFields = [ + { label: 'User ID', value: user.user_id }, + { label: 'Name', value: user.user_name }, + { label: 'User Number', value: user.user_number }, + { label: 'Email', value: user.user_email }, + { label: 'Entity Organization', value: user.entity_name }, + { label: 'Role', value: user.role_name }, + { label: 'Status', value: user.status }, + { label: 'Created Date', value: formatDate(user.created_at) }, + { label: 'Updated Date', value: formatDate(user.updated_at) }, + { label: 'Notes', value: user.notes ? user.notes : 'None' }, + ]; + + const closeBtn = ( + + ); + + return ( + <> + + + Edit User ID: {user.user_id} for {user.user_name} + + +
Edit Selected User
+ + + {({ isSubmitting, dirty }) => ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2000 character limit + + + + + +
+ +
+ )} +
+
+
+ {userFields.map((field, index) => ( + + +

{field.label}:

+ + +

{field.value}

+ +
+ ))} +
+
+
+
+ + setSuccessModalOpen(false)} + className={styles.customModal} + > + {/* Success must be in line with submit button*/} +
+ + +
+ The user data has been successfully updated. +
+ + setErrorModalOpen(false)} + className={styles.customModal} + > +
+ + +
+ {errorMessage} +
+ + ); +}; + +export default EditRecordModal; diff --git a/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewRecordModal.tsx b/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewRecordModal.tsx new file mode 100644 index 00000000..2d2b81a9 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewRecordModal.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { Modal, ModalHeader, Row, Col, ModalBody } from 'reactstrap'; +import { UserRow } from 'hooks/admin'; +import styles from './ViewUsers.module.scss'; +import { formatDate } from 'utils/dateUtil'; + +interface UserDetailsModalProps { + isOpen: boolean; + toggle: () => void; + user: UserRow | null; +} + +const UserDetailsModal: React.FC = ({ + isOpen, + toggle, + user, +}) => { + if (!user) return null; + const closeBtn = ( + + ); + return ( + + + Details for User: {user.user_name} ({user.user_id}) + + + +
+ + + User ID: + + {user.user_id} + + + + Name: + + {user.user_name} + + + + User Number: + + {user.user_number} + + + + Email: + + {user.user_email} + + + + Entity Organization: + + {user.entity_name} + + + + Role: + + {user.role_name} + + + + Status: + + {user.status} + + + + Created Date: + + {formatDate(user.created_at)} + + + + Updated Date: + + {formatDate(user.updated_at)} + + + + Notes: + + {user.notes ? user.notes : 'None'} + +
+
+
+ ); +}; + +export default UserDetailsModal; diff --git a/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.module.scss b/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.module.scss new file mode 100644 index 00000000..1c6ce69a --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.module.scss @@ -0,0 +1,62 @@ +$modal-width: 55%; + +.customModal { + max-width: $modal-width !important; + width: $modal-width; +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; +} + +.customModalTitle { + text-transform: none !important; // Prevent text from being all caps + font-size: 2.5rem; + margin: 0; // Ensure there's no margin +} + +.customLabel { + font-size: 1.5rem; // Adjust the font size as needed +} + +.customSubmitButton { + font-size: 1.5rem; // Increase font size + padding: 0.75rem 1.5rem; // Increase padding +} + +.viewRecord { + font-size: 1.25rem; + line-height: 75%; +} + +.greyRectangle { + background-color: lightgrey; + padding: 1rem; + font-weight: bold; + margin-bottom: 1rem; + border-radius: 0.25rem; +} + +.paginatorContainer { + display: flex; + justify-content: center; /* Centers the child horizontally */ + align-items: center; /* Centers the child vertically */ + height: 100%; /* Adjust as needed */ + padding-top: 20px; +} + +.userkey { + padding-bottom: 0.05em; + padding-right: 0.25em; +} + +.userListing { + padding-left: 0.25em; + padding-right: 0.25em; +} + +.userRow { + padding-bottom: 0.1em; +} diff --git a/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.tsx b/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.tsx new file mode 100644 index 00000000..5ba1476b --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.tsx @@ -0,0 +1,208 @@ +import React, { useState } from 'react'; +import { UserRow, useUsers, useUserFilters } from 'hooks/admin'; +import ViewRecordModal from './ViewRecordModal'; +import EditRecordModal from './EditRecordModal'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import Paginator from 'core-components/Paginator'; +import styles from './ViewUsers.module.scss'; +import { ClearOptionsButton } from 'apcd-components/ClearOptionsButton'; + +export const ViewUsers: React.FC = () => { + const header = [ + 'User ID', + 'Name', + 'Entity Organization', + 'Role', + 'Status', + 'User Number', + 'Actions', + ]; + const { + data: filterData, + isLoading: isFilterLoading, + isError: isFilterError, + } = useUserFilters(); + const [status, setStatus] = useState('Active'); + const [org, setOrg] = useState('All'); + const [page, setPage] = useState(1); + const { + data: userData, + isLoading, + isError, + refetch, + } = useUsers(status, org, page); + const [viewModalOpen, setViewModalOpen] = useState(false); + const [editModalOpen, setEditModalOpen] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); + const [dropdownValue, setDropdownValue] = useState(''); + + const clearSelections = () => { + setStatus('Active'); + setOrg('All'); + setPage(1); + }; + + const handleActionChange = ( + event: React.ChangeEvent, + user: UserRow + ) => { + const action = event.target.value; + setSelectedUser(user); + setDropdownValue(''); + if (action === 'view') { + setViewModalOpen(true); + setEditModalOpen(false); + } else if (action === 'edit') { + setEditModalOpen(true); + setViewModalOpen(false); + } + }; + + const handlePageChange = (newPage: number) => { + if (newPage >= 1 && newPage <= (userData?.total_pages ?? 1)) { + setPage(newPage); + } + }; + + const handleEditSuccess = (updatedUser: UserRow) => { + // Refresh user data after editing is successful + refetch(); + setEditModalOpen(false); + }; + + const closeModal = () => { + setViewModalOpen(false); + setEditModalOpen(false); + setSelectedUser(null); + }; + + if (isFilterLoading || isLoading) { + return ( +
+ +
+ ); + } + + if (isFilterError || isError) { + return
Error loading data
; + } + + return ( +
+

List Users

+
+

+ List of all system users attached to a submitter. +

+
+
+
+ {/* Filter */} + + Filter by Status: + + + + {/* Filter by Organization */} + + Filter by Organization: + + + {status !== 'Active' || org !== 'All' ? ( + + ) : null} +
+
+
+ + + + {header.map((columnName: string, index: number) => ( + + ))} + + + + {userData?.page && userData.page.length > 0 ? ( + userData?.page.map((user: UserRow, rowIndex: number) => ( + + + + + + + + + + )) + ) : ( + + + + )} + +
{columnName}
{user.user_id}{user.user_name}{user.entity_name}{user.role_name}{user.status}{user.user_number} + +
+ No Data available +
+
+
+ +
+ {selectedUser && viewModalOpen && ( + + )} + {selectedUser && editModalOpen && ( + + )} +
+ ); +}; + +export default ViewUsers; diff --git a/apcd_cms/src/client/src/components/Admin/ViewUsers/index.ts b/apcd_cms/src/client/src/components/Admin/ViewUsers/index.ts new file mode 100644 index 00000000..6f7530d3 --- /dev/null +++ b/apcd_cms/src/client/src/components/Admin/ViewUsers/index.ts @@ -0,0 +1,3 @@ +import { ViewUsers } from './ViewUsers'; + +export { ViewUsers }; diff --git a/apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.module.css b/apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.module.css new file mode 100644 index 00000000..97d46906 --- /dev/null +++ b/apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.module.css @@ -0,0 +1,4 @@ +.clearOptions { + padding-top: 5px; + padding-bottom: 5px; +} diff --git a/apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.tsx b/apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.tsx new file mode 100644 index 00000000..d4cc7f15 --- /dev/null +++ b/apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import Button from 'core-components/Button'; +import styles from './ClearOptionsButton.module.css'; + +interface ClearOptionsButtonProps { + onClick: () => void; +} + +const ClearOptionsButton: React.FC = ({ onClick }) => ( + +); + +export default ClearOptionsButton; diff --git a/apcd_cms/src/client/src/components/ClearOptionsButton/index.ts b/apcd_cms/src/client/src/components/ClearOptionsButton/index.ts new file mode 100644 index 00000000..280fd955 --- /dev/null +++ b/apcd_cms/src/client/src/components/ClearOptionsButton/index.ts @@ -0,0 +1,3 @@ +import ClearOptionsButton from './ClearOptionsButton'; + +export { ClearOptionsButton }; diff --git a/apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.module.css b/apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.module.css new file mode 100644 index 00000000..20ecd43d --- /dev/null +++ b/apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.module.css @@ -0,0 +1,17 @@ +.modal { + color: var(--global-color-primary--xx-dark); + padding: 20px; + .h-100 { + padding: 0 10px; + } + + .tr-header { + border-bottom-color: #c6c6c6; + } +} + +.header { + font-weight: 400 !important; + background: var(--global-color-primary--x-light); + display: flex; +} diff --git a/apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.tsx b/apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.tsx new file mode 100644 index 00000000..82bb37f8 --- /dev/null +++ b/apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.tsx @@ -0,0 +1,365 @@ +import React, { useState, useEffect } from 'react'; +import { + Modal, + ModalBody, + ModalHeader, + Label, + FormGroup, + Row, + Col, + Alert, +} from 'reactstrap'; +import { + Formik, + Field, + Form, + ErrorMessage, + useFormik, + FormikHelpers, + FormikProvider, +} from 'formik'; +import { fetchUtil } from 'utils/fetchUtil'; +import * as Yup from 'yup'; +import { ExtensionRow } from 'hooks/admin'; +import { useSubmitterDataPeriods } from 'hooks/entities'; +import QueryWrapper from 'core-wrappers/QueryWrapper'; +import { + convertPeriodLabelToApiValue, + convertApiValueToPeriodLabel, +} from 'utils/dateUtil'; +import styles from './EditExtensionModal.module.css'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; +import Button from 'core-components/Button'; + +interface EditExtensionModalProps { + isVisible: boolean; + onClose: () => void; + extension: ExtensionRow | null; + statusOptions: string[] | undefined; + outcomeOptions: string[] | undefined; + onEditSuccess?: (updatedExtension: ExtensionRow) => void; +} + +interface FormValues { + ext_outcome: string; + ext_status: string; + ext_id: string; + approved_expiration_date: string; + applicable_data_period: string; + notes: string; +} + +const EditExtensionModal: React.FC = ({ + isVisible, + onClose, + extension, + statusOptions, + outcomeOptions, + onEditSuccess, +}) => { + const [showSuccessMessage, setShowSuccessMessage] = useState(false); + const [showErrorMessage, setShowErrorMessage] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + const [extensionFields, setExtensionFields] = useState([ + { + label: 'Applicable Data Period', + value: extension?.applicable_data_period || 'None', + }, + { + label: 'Approved Expiration Date', + value: extension?.approved_expiration_date || 'None', + }, + { label: 'Extension Status', value: extension?.ext_status }, + { label: 'Extension Outcome', value: extension?.ext_outcome }, + { label: 'Extension Notes', value: extension?.notes || 'None' }, + ]); + const { + data: submitterData, + isLoading: submitterDataLoading, + error: submitterDataError, + } = useSubmitterDataPeriods(extension?.submitter_id); + + if (!extension) return null; + + // Use the custom hook to get form fields and validation + const useFormFields = () => { + const initialValues: FormValues = { + ...extension, + ext_id: extension?.ext_id, + notes: extension?.notes || 'None', // Set notes to 'None' if it is null + }; + + const validationSchema = Yup.object({ + notes: Yup.string() + .max(2000, 'Notes cannot exceed 2000 characters') + .nullable(), + }); + + return { initialValues, validationSchema }; + }; + const { initialValues, validationSchema } = useFormFields(); + + const onSubmit = async ( + values: FormValues, + actions: FormikHelpers + ) => { + const { ext_id } = values; + const api_values = { + ...values, + applicable_data_period: convertPeriodLabelToApiValue( + values['applicable_data_period'] + ), + }; + const url = `administration/update-extension/${ext_id}/`; + + try { + setShowSuccessMessage(false); + setShowErrorMessage(false); + const response = await fetchUtil({ + url, + method: 'PUT', + body: api_values, + }); + + if (onEditSuccess && response) { + onEditSuccess(response); + setExtensionFields([ + { + label: 'Applicable Data Period', + value: + convertApiValueToPeriodLabel(values.applicable_data_period) || + 'None', + }, + { + label: 'Approved Expiration Date', + value: values.approved_expiration_date || 'None', + }, + { label: 'Extension Status', value: values.ext_status }, + { label: 'Extension Outcome', value: values.ext_outcome }, + { label: 'Extension Notes', value: values.notes || 'None' }, + ]); + } + + setShowSuccessMessage(true); + } catch (error: any) { + if (error.response && error.response.data) { + // Use error message from the server response + setErrorMessage( + error.response.data.message || + 'An error occurred while saving the data. Please try again.' + ); + } else { + // Use generic error message + setErrorMessage( + 'An error occurred while saving the data. Please try again.' + ); + } + setShowErrorMessage(true); + } finally { + actions.setSubmitting(false); + } + }; + + const formik = useFormik({ + initialValues, + validationSchema, + onSubmit, + enableReinitialize: true, + }); + + const handleClose = () => { + setShowSuccessMessage(false); + setShowErrorMessage(false); + }; + + const closeBtn = ( + + ); + + return ( + <> + + + Edit Extension ID {extension.ext_id} for {extension.org_name} + + +

Edit Selected Extension

+ + +
+ + + + + {submitterData?.data_periods?.map((item) => ( + + ))} + +
+ Current: {extension.applicable_data_period} +
+
+ + + + +
+ Current:{' '} + {extension.approved_expiration_date + ? new Date( + extension.approved_expiration_date + ).toLocaleDateString() + : 'None'} +
+
+ + + + + {statusOptions?.map( + (opt) => + opt.value !== 'All' && ( + + ) + )} + + + + + + + {outcomeOptions?.map((opt) => ( + + ))} + + + + + + +
2000 character limit
+
+ +
+
+ + Success: The exception data has been successfully updated. + + + Error: {errorMessage} + + +
+
+
+
+

Current Extension Information

+
+ {extensionFields.map((field, index) => ( + + +

{field.label}:

+ + +

{field.value}

+ +
+ ))} +
+
+
+ + ); +}; + +export default EditExtensionModal; diff --git a/apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.module.css b/apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.module.css new file mode 100644 index 00000000..a3753242 --- /dev/null +++ b/apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.module.css @@ -0,0 +1,26 @@ +.modal { + color: var(--global-color-primary--xx-dark); + padding: 20px; + .h-100 { + padding: 0 10px; + } + + .tr-header { + border-bottom-color: #c6c6c6; + } +} + +.header { + font-weight: 400 !important; + background: var(--global-color-primary--x-light); + display: flex; +} + +.verticalDataList { + width: 100%; + padding-left: 40px; +} + +.verticalDataValue { + padding-left: 2.5em; +} diff --git a/apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.tsx b/apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.tsx new file mode 100644 index 00000000..ab877972 --- /dev/null +++ b/apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { Modal, ModalHeader, ModalBody } from 'reactstrap'; +import { ExtensionRow } from 'hooks/admin'; +import styles from './ViewExtensionModal.module.css'; + +const ViewExtensionModal: React.FC<{ + extension: ExtensionRow; + isVisible: boolean; + onClose: () => void; +}> = ({ extension, isVisible, onClose }) => { + const closeBtn = ( + + ); + return ( + + + Extension Details ID {extension.ext_id} for {extension.org_name} + + + +
+

Details

+
+
+
Created
+
{extension.created}
+
Entity Organization
+
{extension.org_name}
+
Requestor
+
{extension.requestor}
+
Requestor Email
+
+ {extension.requestor_email} +
+
Extension Type
+
{extension.type}
+
Status
+
{extension.ext_status}
+
Outcome
+
{extension.ext_outcome}
+
Applicable Data Period
+
+ {extension.applicable_data_period} +
+
Current Expected Date
+
+ {extension.current_expected_date} +
+
Requested Target Date
+
+ {extension.requested_target_date} +
+
Approved Expiration Date
+
+ {extension.approved_expiration_date} +
+
Extension Justification
+
+ {extension.explanation_justification} +
+
Extension Notes
+
{extension.notes}
+
Last Updated
+
{extension.updated_at}
+
+
+
+
+
+ ); +}; + +export default ViewExtensionModal; diff --git a/apcd_cms/src/client/src/components/Forms/Registrations/FormContact.tsx b/apcd_cms/src/client/src/components/Forms/Registrations/FormContact.tsx new file mode 100644 index 00000000..d529ae5d --- /dev/null +++ b/apcd_cms/src/client/src/components/Forms/Registrations/FormContact.tsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { Field, ErrorMessage } from 'formik'; +import { FormGroup, Label, FormFeedback } from 'reactstrap'; +import { TextFormField } from './TextFormField'; +import styles from './RegistrationForm.module.css'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik/FieldWrapperFormik'; + +export const RegistrationContact: React.FC<{ index: number }> = ({ index }) => { + return ( +
+
+ CONTACT {index + 1} +
+ + + + + + +
+
+ + + {' '} + North American Numbering Plan{' '} + + e.g. 123 456-7890… + +
    +
  • + 123-456-7890 +
  • +
  • + (123) 456-7890 +
  • +
  • + 123 456 7890 +
  • +
  • + 123.456.7890 +
  • +
  • + +1 (123) 456-7890 +
  • +
+
+
+ + + + + + + +
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Forms/Registrations/FormEntity.tsx b/apcd_cms/src/client/src/components/Forms/Registrations/FormEntity.tsx new file mode 100644 index 00000000..d38d27eb --- /dev/null +++ b/apcd_cms/src/client/src/components/Forms/Registrations/FormEntity.tsx @@ -0,0 +1,167 @@ +import React from 'react'; +import { Field, ErrorMessage } from 'formik'; +import { FormGroup, Label, FormFeedback } from 'reactstrap'; +import { TextFormField } from './TextFormField'; +import styles from './RegistrationForm.module.css'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; + +export const RegistrationEntity: React.FC<{ index: number }> = ({ index }) => { + return ( +
+
+ ENTITY {index + 1} +
+ + + +
+ + + + + + + + + +
Type of Plan
+ +
+ + {['Commercial', 'Medicare', 'Medicaid'].map((planType) => ( + + + + ))} + + + +
File Submission
+ + + {[ + 'Eligibility/Enrollment', + 'Provider', + 'Medical', + 'Pharmacy', + 'Dental', + ].map((fileType) => ( + + + + ))} + + + +
+ Coverage Estimates + + {' '} + (Inclusive of all claims as of December 31 of previous year.) + +
+ + + + +
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.module.css b/apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.module.css new file mode 100644 index 00000000..6533b89a --- /dev/null +++ b/apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.module.css @@ -0,0 +1,24 @@ +.isInvalid { + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.isRequired { + color: red; +} + +.contactsAndEntitiesButtons { + background-color: var(--global-color-accent--normal); + border-color: var(--global-color-accent--normal); + color: var(--global-color-primary--xx-light); +} + +.boldedHeader { + font-weight: bold; +} + +.spacedHeader { + margin-top: 2rem; +} diff --git a/apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx b/apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx new file mode 100644 index 00000000..c1e17376 --- /dev/null +++ b/apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx @@ -0,0 +1,552 @@ +import React, { useEffect } from 'react'; +import { Formik, Form, Field } from 'formik'; +import * as Yup from 'yup'; +import { FormGroup, Label } from 'reactstrap'; +import Button from 'core-components/Button'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { + RegistrationFormValues, + transformToRegistrationFormValues, + useRegFormData, + usePostRegistration, +} from 'hooks/registrations'; +import USStates from './USStates.fixture'; +import { TextFormField } from './TextFormField'; +import { RegistrationEntity } from './FormEntity'; +import { RegistrationContact } from './FormContact'; +import SectionMessage from 'core-components/SectionMessage'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; +import styles from './RegistrationForm.module.css'; + +const validationSchema = Yup.object().shape({ + reg_year: Yup.string() + .matches(/^(202[3-9]|20[3-9][0-9]|2100)$/, { + message: 'Registration year must be 2023 or later', + }) + .required('Registration year is required'), + business_name: Yup.string().required('Business name is required'), + mailing_address: Yup.string().required('Mailing address is required'), + city: Yup.string().required('City is required'), + zip_code: Yup.string() + .matches(/^\d{5}(-\d{4})?$/, { message: 'ZIP is not properly formatted' }) + .required('ZIP Code is required'), + entities: Yup.array().of( + Yup.object() + .shape({ + entity_name: Yup.string().required('Entity name is required'), + fein: Yup.string().matches(/^\d{2}-\d{7}$/, { + message: 'FEIN is not properly formatted', + }), + license_number: Yup.string().matches(/^(?!0+$)[0-9]{1,10}$/, { + message: 'License no. is not properly formatted', + }), + naic_company_code: Yup.string().matches(/^(?!0+$)[0-9]{1,10}$/, { + message: 'NAIC code is not properly formatted', + }), + types_of_plans_commercial: Yup.boolean(), + types_of_plans_medicare: Yup.boolean(), + types_of_plans_medicaid: Yup.boolean(), + types_of_files_eligibility_enrollment: Yup.boolean(), + types_of_files_provider: Yup.boolean(), + types_of_files_medical: Yup.boolean(), + types_of_files_pharmacy: Yup.boolean(), + types_of_files_dental: Yup.boolean(), + total_covered_lives: Yup.number() + .typeError('Must be an integer') + .min(0) + .required('Total covered lives is required'), + claims_encounters_volume: Yup.number() + .typeError('Must be an integer') + .min(0) + .required('Claims and Encounters volume is required'), + total_claims_value: Yup.number() + .typeError('Must be a number') + .min(0) + .required('Total Claims Value is required') + .test( + 'maxDigitsAfterDecimal', + 'USD amount can only have two digits after decimal', + (number) => Number.isInteger(number * 10 ** 2) + ), + }) + .test(function (value) { + if (!value.fein && !value.license_number && !value.naic_company_code) { + return this.createError({ + message: 'Please fill in at least one Number/Code.', + path: this.path + '.fein', + }); + } + return true; + }) + .test(function (value) { + if ( + !value.types_of_plans_commercial && + !value.types_of_plans_medicare && + !value.types_of_plans_medicaid + ) { + return this.createError({ + message: 'Please select at least one plan type.', + path: this.path + '.types_of_plans_hidden', + }); + } + return true; + }) + .test(function (value) { + if ( + !value.types_of_files_medical && + !value.types_of_files_pharmacy && + !value.types_of_files_dental + ) { + return this.createError({ + message: 'Please select at least one claims file type (see above).', + path: this.path + '.types_of_files_hidden', + }); + } + return true; + }) + ), + contacts: Yup.array().of( + Yup.object().shape({ + contact_type: Yup.string().required('Company role is required'), + contact_name: Yup.string().required('Contact name is required'), + contact_phone: Yup.string() + .required('Phone number is required') + .matches(/^(\+0?1\s)?\(?\d{3}\)?[\s.\-]\d{3}[\s.\-]\d{4}$/, { + message: 'Phone number is not properly formatted', + }), + contact_email: Yup.string() + .email('Invalid email') + .required('Email is required'), + }) + ), +}); + +const initialValues: RegistrationFormValues = { + on_behalf_of: 'true', + reg_year: '', + type: 'carrier', + business_name: '', + mailing_address: '', + city: '', + state: 'AL', + zip_code: '', + reg_id: -1, + entities: [ + { + entity_name: '', + fein: '', + license_number: '', + naic_company_code: '', + types_of_plans_commercial: false, + types_of_plans_medicare: false, + types_of_plans_medicaid: false, + types_of_plans_hidden: false, + types_of_files_eligibility_enrollment: true, + types_of_files_provider: false, + types_of_files_medical: false, + types_of_files_pharmacy: false, + types_of_files_dental: false, + types_of_files_hidden: false, + total_covered_lives: '', + claims_encounters_volume: '', + total_claims_value: '', + entity_id: -1, + }, + ], + contacts: [ + { + contact_type: '', + contact_name: '', + contact_phone: '', + contact_email: '', + contact_notifications: false, + contact_id: -1, + }, + ], +}; + +const initialTouched = { + on_behalf_of: true, + type: true, + state: true, + entities: [ + { + types_of_plans_commercial: true, + types_of_plans_medicare: true, + types_of_plans_medicaid: true, + types_of_files_eligibility_enrollment: true, + types_of_files_provider: true, + types_of_files_medical: true, + types_of_files_pharmacy: true, + types_of_files_dental: true, + }, + ], +}; + +export const RegistrationForm: React.FC<{ + isEdit?: boolean; + inputValues?: RegistrationFormValues; + isModal?: boolean; + status_options?: string[]; + onSuccessCallback?: () => void; +}> = ({ + isEdit = false, + inputValues, + isModal = false, + status_options = [], + onSuccessCallback = () => {}, +}) => { + const [searchParams] = useSearchParams(); + const { data, isLoading, isError } = useRegFormData( + searchParams.get('reg_id') + ); + const { + mutate: submitForm, + isLoading: registrationSubmissionPending, + isSuccess, + data: registrationResponse, + error: registrationError, + } = usePostRegistration(); + + const handleSubmit = async (values: RegistrationFormValues) => { + const url = isEdit + ? `administration/request-to-submit/api/${inputValues?.reg_id ?? -1}/` + : `register/request-to-submit/api/`; + submitForm({ url, body: values }); + }; + const handleClick = () => { + window.location.href = '/workbench/dashboard'; + }; + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (isError) { + return
Error loading form
; + } + + return ( +
+
+ {!isModal ? ( + <> +

Request to Submit

+
+ +

+ This form should be completed and submitted to register as a data + submitter. Please review the + + {' '} + Data Submission Guide{' '} + + for details about completing and submitting this form, paying + special attention to the schedule of submissions including test + files, historical files, and monthly files. +

+ +
+ + ) : ( + '' + )} + + {({ values, setFieldValue, resetForm, dirty }) => ( + useEffect(() => { + if (isSuccess) { + resetForm(); + } + }, [isSuccess, resetForm]), + isSuccess ? ( + <> +
+ Your {isEdit ? 'update' : 'submission'} was successful. Your + registration ID is: {registrationResponse?.reg_id}. +
+ {isModal ? ( + + ) : ( + + )} + + ) : ( +
+

Organization

+ {status_options.length > 0 ? ( + + + {status_options.map((item, index) => ( + + ))} + + + ) : ( + <> + )} + + + + + + + + + + + + + + + + + + + + {USStates.map((USState) => ( + + ))} + + + +
+

+ Entity Being Registered + + (If single company, enter the same organization as above.) + +

+ {values.entities.map((entity, index) => ( + + ))} + {values.entities.length === 5 && ( +

+ If you need to associate more than 5 entities with your + registration, + + {' '} + submit a ticket{' '} + + with your additional entries and your registration ID + (displayed after submitting this form). +

+ )} +
+ {' '} + +
+
+

Contact Information

+ {values.contacts.map((contact, index) => ( + + ))} +
+ {' '} + +
+
+ +
+ {registrationError && ( +
+ + {registrationError.message ?? + 'An error occurred while saving the data. Please try again.'} + +
+ )} + + ) + )} +
+ +
+
+

+ + ¹ Third Party Administrator / Administrative Services Only + (TPA/ASO) +
+ ² Federal Employer Identification Number (FEIN) +
+ ³ National Association of Insurance Commissioners (NAIC) +
+ ⁴ United States Dollar (USD) +
+
+

+
+
+
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Forms/Registrations/TextFormField.tsx b/apcd_cms/src/client/src/components/Forms/Registrations/TextFormField.tsx new file mode 100644 index 00000000..20226e04 --- /dev/null +++ b/apcd_cms/src/client/src/components/Forms/Registrations/TextFormField.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Field, ErrorMessage } from 'formik'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; + +/* Component to re-use for text input fields */ +export const TextFormField: React.FC<{ + name: string; + label: any; + helpText?: any; + required?: boolean; +}> = ({ name, label, helpText, required = false }) => { + return ( + + + + ); +}; diff --git a/apcd_cms/src/client/src/components/Forms/Registrations/USStates.fixture.ts b/apcd_cms/src/client/src/components/Forms/Registrations/USStates.fixture.ts new file mode 100644 index 00000000..ad59fb16 --- /dev/null +++ b/apcd_cms/src/client/src/components/Forms/Registrations/USStates.fixture.ts @@ -0,0 +1,59 @@ +const USStates = [ + { value: 'AL', label: 'AL - Alabama' }, + { value: 'AK', label: 'AK - Alaska' }, + { value: 'AS', label: 'AS - American Samoa' }, + { value: 'AZ', label: 'AZ - Arizona' }, + { value: 'AR', label: 'AR - Arkansas' }, + { value: 'CA', label: 'CA - California' }, + { value: 'CO', label: 'CO - Colorado' }, + { value: 'CT', label: 'CT - Connecticut' }, + { value: 'DE', label: 'DE - Delaware' }, + { value: 'DC', label: 'DC - District of Columbia' }, + { value: 'FL', label: 'FL - Florida' }, + { value: 'GA', label: 'GA - Georgia' }, + { value: 'HI', label: 'HI - Hawaii' }, + { value: 'ID', label: 'ID - Idaho' }, + { value: 'IL', label: 'IL - Illinois' }, + { value: 'IN', label: 'IN - Indiana' }, + { value: 'IA', label: 'IA - Iowa' }, + { value: 'KS', label: 'KS - Kansas' }, + { value: 'KY', label: 'KY - Kentucky' }, + { value: 'LA', label: 'LA - Louisiana' }, + { value: 'ME', label: 'ME - Maine' }, + { value: 'MD', label: 'MD - Maryland' }, + { value: 'MA', label: 'MA - Massachusetts' }, + { value: 'MI', label: 'MI - Michigan' }, + { value: 'MN', label: 'MN - Minnesota' }, + { value: 'MS', label: 'MS - Mississippi' }, + { value: 'MO', label: 'MO - Missouri' }, + { value: 'MP', label: 'MP - Northern Mariana Islands' }, + { value: 'MT', label: 'MT - Montana' }, + { value: 'NE', label: 'NE - Nebraska' }, + { value: 'NV', label: 'NV - Nevada' }, + { value: 'NH', label: 'NH - New Hampshire' }, + { value: 'NJ', label: 'NJ - New Jersey' }, + { value: 'NM', label: 'NM - New Mexico' }, + { value: 'NY', label: 'NY - New York' }, + { value: 'NC', label: 'NC - North Carolina' }, + { value: 'ND', label: 'ND - North Dakota' }, + { value: 'OH', label: 'OH - Ohio' }, + { value: 'OK', label: 'OK - Oklahoma' }, + { value: 'OR', label: 'OR - Oregon' }, + { value: 'PA', label: 'PA - Pennsylvania' }, + { value: 'PR', label: 'PR - Puerto Rico' }, + { value: 'RI', label: 'RI - Rhode Island' }, + { value: 'SC', label: 'SC - South Carolina' }, + { value: 'SD', label: 'SD - South Dakota' }, + { value: 'TN', label: 'TN - Tennessee' }, + { value: 'TX', label: 'TX - Texas' }, + { value: 'UT', label: 'UT - Utah' }, + { value: 'VT', label: 'VT - Vermont' }, + { value: 'VI', label: 'VI - Virgin Islands' }, + { value: 'VA', label: 'VA - Virginia' }, + { value: 'WA', label: 'WA - Washington' }, + { value: 'WV', label: 'WV - West Virginia' }, + { value: 'WI', label: 'WI - Wisconsin' }, + { value: 'WY', label: 'WY - Wyoming' }, +]; + +export default USStates; diff --git a/apcd_cms/src/client/src/components/Forms/Registrations/index.ts b/apcd_cms/src/client/src/components/Forms/Registrations/index.ts new file mode 100644 index 00000000..6492da6e --- /dev/null +++ b/apcd_cms/src/client/src/components/Forms/Registrations/index.ts @@ -0,0 +1,2 @@ +// index.ts +export * from './RegistrationForm'; diff --git a/apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.module.css b/apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.module.css new file mode 100644 index 00000000..20ecd43d --- /dev/null +++ b/apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.module.css @@ -0,0 +1,17 @@ +.modal { + color: var(--global-color-primary--xx-dark); + padding: 20px; + .h-100 { + padding: 0 10px; + } + + .tr-header { + border-bottom-color: #c6c6c6; + } +} + +.header { + font-weight: 400 !important; + background: var(--global-color-primary--x-light); + display: flex; +} diff --git a/apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.tsx b/apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.tsx new file mode 100644 index 00000000..9166fb67 --- /dev/null +++ b/apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { Modal, ModalHeader, ModalBody } from 'reactstrap'; +import { + transformToRegistrationFormValues, + RegistrationFormValues, + useAdminRegistration, +} from 'hooks/registrations'; +import { RegistrationForm } from 'apcd-components/Forms/Registrations'; + +const EditRegistrationModal: React.FC<{ + reg_id: number; + isVisible: boolean; + status_options: string[]; + onClose: () => void; +}> = ({ reg_id, isVisible, status_options, onClose }) => { + const { data, isLoading, error } = useAdminRegistration(reg_id); + + if (isLoading) return
Loading...
; + if (error) return
Error: {error}
; + if (!data) return
No data Found.
; + + const form_values: RegistrationFormValues = + transformToRegistrationFormValues(data); + + const closeBtn = ( + + ); + + return ( + + Edit Registration + + option !== 'All' && option !== 'None' + )} + onSuccessCallback={onClose} + /> + + + ); +}; + +export default EditRegistrationModal; diff --git a/apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.module.css b/apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.module.css new file mode 100644 index 00000000..624f460b --- /dev/null +++ b/apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.module.css @@ -0,0 +1,7 @@ +.paginatorContainer { + display: flex; + justify-content: center; /* Centers the child horizontally */ + align-items: center; /* Centers the child vertically */ + height: 100%; /* Adjust as needed */ + padding-top: 20px; +} diff --git a/apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.tsx b/apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.tsx new file mode 100644 index 00000000..52a7687a --- /dev/null +++ b/apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.tsx @@ -0,0 +1,194 @@ +import React, { useEffect, useState } from 'react'; +import { RegistrationRow } from 'hooks/registrations'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import Paginator from 'core-components/Paginator'; +import ViewRegistrationModal from 'apcd-components/Registrations/ViewRegistrationModal/ViewRegistrationModal'; +import EditRegistrationModal from 'apcd-components/Registrations/EditRegistrationModal/EditRegistrationModal'; +import styles from './RegistrationList.module.css'; +import { ClearOptionsButton } from 'apcd-components/ClearOptionsButton'; + +export const RegistrationList: React.FC<{ + useDataHook: any; + isAdmin?: boolean; +}> = ({ useDataHook, isAdmin = false }) => { + const initStateFilter = isAdmin ? 'Received' : ''; // for admin listing, show records w/ status 'Received' by default + const [status, setStatus] = useState(initStateFilter); + const [org, setOrg] = useState('All'); + const [page, setPage] = useState(1); + const { data, isLoading, isError, refetch } = useDataHook(status, org, page); + const [isViewModalOpen, setIsViewModalOpen] = useState(false); + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + + const [selectedRegistration, setSelectedRegistration] = + useState(null); + + useEffect(() => { + refetch(); + }, [status, org, page, refetch]); + + const clearSelections = () => { + setStatus(initStateFilter); + setOrg(''); + setPage(1); + }; + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (isError) { + return ( + <> +

+ An error occurred loading your registrations. For help,{' '} + + Please submit a ticket. + +

+ + Back to Home + + + ); + } + + const openAction = ( + event: React.ChangeEvent, + reg_id: number + ) => { + const actionsDropdown = event.target; + const selectedOption = actionsDropdown.value; + setSelectedRegistration( + data?.page.find((x) => x.reg_id === reg_id) ?? null + ); + if (selectedOption == 'viewRegistration') { + setIsViewModalOpen(true); + } else if (selectedOption == 'editRegistration') { + setIsEditModalOpen(true); + } else if (selectedOption == 'renewRegistration') { + var xhr, url; + url = `/register/request-to-submit/?reg_id=${reg_id}`; + xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.send(); + window.location.href = url; + } + actionsDropdown.selectedIndex = 0; + }; + + return ( +
+
+
+ {/* Filter */} + + Filter by Status: + + + + + Filter by Organization: + + + {data?.selected_status !== initStateFilter || data?.selected_org ? ( + + ) : null} +
+
+ + + + {data?.header.map((columnName: string, index: number) => ( + + ))} + + + + {data?.page && data.page.length > 0 ? ( + data?.page.map((row: RegistrationRow, rowIndex: number) => ( + + + + + + + + + )) + ) : ( + + + + )} + +
{columnName}
{row.biz_name}{row.year ? row.year : 'None'}{row.type}{row.location}{row.reg_status ? row.reg_status : 'None'} + +
+ No Data available +
+
+ +
+ {selectedRegistration && ( + <> + setIsViewModalOpen(false)} + /> + setIsEditModalOpen(false)} + /> + + )} +
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Registrations/RegistrationList/index.ts b/apcd_cms/src/client/src/components/Registrations/RegistrationList/index.ts new file mode 100644 index 00000000..0257cc50 --- /dev/null +++ b/apcd_cms/src/client/src/components/Registrations/RegistrationList/index.ts @@ -0,0 +1,4 @@ +// index.ts +import { RegistrationList } from './RegistrationList'; + +export { RegistrationList }; diff --git a/apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.module.css b/apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.module.css new file mode 100644 index 00000000..a3753242 --- /dev/null +++ b/apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.module.css @@ -0,0 +1,26 @@ +.modal { + color: var(--global-color-primary--xx-dark); + padding: 20px; + .h-100 { + padding: 0 10px; + } + + .tr-header { + border-bottom-color: #c6c6c6; + } +} + +.header { + font-weight: 400 !important; + background: var(--global-color-primary--x-light); + display: flex; +} + +.verticalDataList { + width: 100%; + padding-left: 40px; +} + +.verticalDataValue { + padding-left: 2.5em; +} diff --git a/apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.tsx b/apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.tsx new file mode 100644 index 00000000..7c7b733d --- /dev/null +++ b/apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.tsx @@ -0,0 +1,180 @@ +import React from 'react'; +import { Modal, ModalHeader, ModalBody } from 'reactstrap'; +import { useAdminRegistration } from 'hooks/registrations'; +import styles from './ViewRegistrationModal.module.css'; + +const ViewRegistrationModal: React.FC<{ + reg_id: number; + isVisible: boolean; + onClose: () => void; +}> = ({ reg_id, isVisible, onClose }) => { + const { data, isLoading, error } = useAdminRegistration(reg_id); + + if (isLoading) return
Loading...
; + if (error) return
Error: {error}
; + if (!data) return
No data Found.
; + + const { + for_self, + year, + type, + biz_name, + address, + city, + state, + zip, + status, + entities, + contacts, + } = data; + + const closeBtn = ( + + ); + + return ( + + View Registration + + +
+

Organization

+
+
+
On behalf of
+
+ {for_self ? 'Self' : 'Other'} +
+
Registration Year
+
+ {year ? year : 'None'} +
+
Type
+
{type}
+
Business Name
+
{biz_name}
+
Mailing Address
+
{address}
+
{`${city}, ${state}`}
+
{zip}
+
Registration Status
+
{status}
+
+
+ +
+

Entity/Entities Being Registered

+ {entities.map((entity, index) => ( +
+
Entity {index + 1}
+
+
Name
+
{entity.ent_name}
+
FEIN
+
+ {entity.fein ? entity.fein : 'None'} +
+
License Number
+
+ {entity.license ? entity.license : 'None'} +
+
NAIC Company Code
+
+ {entity.naic ? entity.naic : 'None'} +
+
Type of Plan
+
+
+
Types of Plans
+ {Object.entries(entity.plans_type).map( + ([plan_type, selected]) => + selected && ( +
+ {plan_type} +
+ ) + )} +
+
+
File Submission
+
+
+
Types of Files
+ {Object.entries(entity.files_type).map( + ([file_type, selected]) => + selected && ( +
+ {file_type} +
+ ) + )} +
+
+
+ Coverage Estimates{' '} + + (Inclusive of all claims as of December 31 of previous + year.) + +
+
Total Covered Lives
+
+ {entity.no_covered} +
+
+ Claims and Encounters Volume +
+
+ {entity.claim_and_enc_vol} +
+
Total Claims Value (USD)
+
{entity.claim_val}
+
+
+ ))} + +
+

Contact Information

+ {contacts.map((contact, index) => ( +
+
Contact {index + 1}
+
+
Role
+
{contact.role}
+
Name
+
{contact.name}
+
Phone
+
{contact.phone}
+
Email
+
{contact.email}
+
+ + Should {contact.notif ? '' : 'not'} receive system + notifications + +
+
+
+ ))} +
+
+
+ ); +}; + +export default ViewRegistrationModal; diff --git a/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.module.css b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.module.css new file mode 100644 index 00000000..624f460b --- /dev/null +++ b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.module.css @@ -0,0 +1,7 @@ +.paginatorContainer { + display: flex; + justify-content: center; /* Centers the child horizontally */ + align-items: center; /* Centers the child vertically */ + height: 100%; /* Adjust as needed */ + padding-top: 20px; +} diff --git a/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.tsx b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.tsx new file mode 100644 index 00000000..a2f3c7d4 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.tsx @@ -0,0 +1,234 @@ +import React, { useEffect, useMemo, useState } from 'react'; +import { + useListSubmissions, + FileSubmissionRow, + useSubmissionFilters, + FileSubmissionLogsModalContent, +} from 'hooks/submissions'; +import { Entities, useEntities } from 'hooks/entities'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import Button from 'core-components/Button'; +import SectionMessage from 'core-components/SectionMessage'; +import Paginator from 'core-components/Paginator'; +import styles from './ViewSubmissions.module.css'; +import { Link } from 'react-router-dom'; +import { ViewSubmissionLogsModal } from './ViewSubmissionsModal'; +import { formatDate } from 'utils/dateUtil'; +import { titleCase } from 'utils/stringUtil'; +import { ClearOptionsButton } from 'apcd-components/ClearOptionsButton'; + +export const ViewFileSubmissions: React.FC = () => { + const header = [ + 'Received', + 'Entity Organization', + 'File Name', + 'Outcome', + 'Status', + 'Last Updated', + 'Payor Code', + 'Actions', + ]; + const { + data: filterData, + isLoading: isFilterLoading, + isError: isFilterError, + } = useSubmissionFilters(); + + const [status, setStatus] = useState('All'); + const [sort, setSort] = useState('Newest Received'); + const [page, setPage] = useState(1); + const [submitterId, setSubmitterId] = useState('All'); + const [payorCode, setPayorCode] = useState('All'); + const [submitterPayorCode, setSubmitterPayorCode] = useState('All'); + const [viewModalOpen, setViewModalOpen] = useState(false); + const [selectedSubmission, setSelectedSubmission] = + useState(null); + const [selectedSubmissionLog, setSelectedSubmissionLog] = useState< + FileSubmissionLogsModalContent[] + >([]); + + const closeModal = () => { + setViewModalOpen(false); + setSelectedSubmission(null); + }; + + const { + data: submissionData, + isLoading: isSubmissionLoading, + isError: isSubmissionError, + refetch, + } = useListSubmissions(status, sort, submitterId, payorCode, page); + + useEffect(() => { + if (submitterId && payorCode) { + setSubmitterPayorCode(`${submitterId},${payorCode}`); + } else { + setSubmitterPayorCode('All'); + } + }, [submitterId, payorCode]); + + useEffect(() => { + refetch(); + }, [status, sort, page]); + + const { + data: submitterData, + isLoading: entitiesLoading, + error: entitiesError, + } = useEntities(); + + if (isSubmissionLoading) { + return ; + } + + if (isSubmissionError) { + return ( + + There was an error loading the page.{' '} + + Please submit a ticket. + + + ); + } + + const clearSelections = () => { + setStatus('All'); + setSort('Newest Received'); + setSubmitterId('All'); + setPayorCode('All'); + setPage(1); + }; + + return ( +
+
+
+ {/* Filter */} + + Filter by Status: + + + + Sort by: + + + + Payor Code: + + + {status !== 'All' || + sort !== 'Newest Received' || + submitterId !== 'All' || + payorCode !== 'All' ? ( + + ) : null} +
+
+ + + + {header.map((columnName: string, index: number) => ( + + ))} + + + + {submissionData?.page && submissionData.page.length > 0 ? ( + submissionData?.page.map( + (row: FileSubmissionRow, rowIndex: number) => ( + + + + + + + + + + + ) + ) + ) : ( + + + + )} + +
{columnName}
{formatDate(row.received_timestamp)}{titleCase(row.entity_name)}{titleCase(row.file_name)}{titleCase(row.outcome)}{titleCase(row.status)}{formatDate(row.updated_at)}{row.payor_code} + +
+ No Data available +
+
+ +
+ {selectedSubmission && viewModalOpen && ( + + )} +
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissionsModal.tsx b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissionsModal.tsx new file mode 100644 index 00000000..dd3a4b6c --- /dev/null +++ b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissionsModal.tsx @@ -0,0 +1,102 @@ +import { FileSubmissionLogsModalContent } from 'hooks/submissions'; +import React from 'react'; +import { Modal, ModalBody, ModalHeader } from 'reactstrap'; +import { titleCase } from 'utils/stringUtil'; +import { Link } from 'react-router-dom'; + +interface ViewSubmissionLogsModalProps { + submission_logs: FileSubmissionLogsModalContent[]; + isOpen: boolean; + parentToggle: () => void; + isAdminUser?: boolean; +} + +export const ViewSubmissionLogsModal: React.FC< + ViewSubmissionLogsModalProps +> = ({ submission_logs, isOpen, parentToggle, isAdminUser = false }) => { + const closeBtn = ( + + ); + + return ( + <> + + + View Logs + + +
+
+ {submission_logs.length > 0 ? ( + submission_logs.map((log: any, index: number) => ( +
+
+
Log ID
+
{log.log_id}
+
Entity Organization
+
+ {titleCase(log.entity_name)} +
+
File Type
+
+ {titleCase(log.file_type)} +
+
Validation Suite
+
+ {titleCase(log.validation_suite)} +
+
Outcome
+
+ {titleCase(log.outcome)} +
+
HTML Log
+
+ {log.has_html_log === 1 && ( + + Download + + )} +
+
JSON Log
+
+ {log.has_json_log === 1 && ( + + Download + + )} +
+
+
+
+ )) + ) : ( +
+ No logs found for this submission +
+ )} +
+
+
+
+ + ); +}; diff --git a/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/index.ts b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/index.ts new file mode 100644 index 00000000..acc68f6e --- /dev/null +++ b/apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/index.ts @@ -0,0 +1,4 @@ +import { ViewFileSubmissions } from './ViewSubmissions'; +import { ViewSubmissionLogsModal } from './ViewSubmissionsModal'; + +export { ViewFileSubmissions, ViewSubmissionLogsModal }; diff --git a/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.module.css b/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.module.css new file mode 100644 index 00000000..3571c597 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.module.css @@ -0,0 +1,56 @@ +/*Text Style*/ +.justificationAsterisk { + padding-left: 0; + margin-left: 0; +} + +/* Field Sizes */ +.thresholdRequested, +.expirationDate { + min-width: 15ch; +} +.fieldRows { + display: flex; + gap: 5rem; + margin-top: 1rem; + margin-bottom: 1rem; +} +.fieldRows input { + font-size: inherit; +} +.loadingField { + display: inline-flex; + justify-content: flex-start; + align-items: center; + height: 100%; + width: 100%; +} +.requiredThreshold { + background-color: #e9ecef; + color: #6c757d; + border-color: #ced4da; +} +.requiredThreshold, +.thresholdRequested { + -webkit-appearance: none; + margin: 0; + -moz-appearance: textfield; +} +.termsCheckbox input { + position: unset; + margin-left: 0; +} + +.justification { + font-size: unset; +} +.isInvalid { + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} +/* To match CEP styles of required fields */ +.requiredBadge { + margin-left: 10px; +} diff --git a/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.tsx b/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.tsx new file mode 100644 index 00000000..869672a5 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.tsx @@ -0,0 +1,211 @@ +import React, { useState, useEffect } from 'react'; +import { useFormikContext, Field, ErrorMessage } from 'formik'; +import { cdlObject, useCDLs, cdl } from 'hooks/cdls'; +import { Entities, useEntities } from 'hooks/entities'; +import styles from './ExceptionForm.module.css'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import SectionMessage from 'core-components/SectionMessage'; +import { Link } from 'react-router-dom'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; + +export const ExceptionForm: React.FC<{ index: number }> = ({ index }) => { + const [cdlData, setCdlData] = useState(); + const [selectedCDL, setSelectedCDL] = useState(); + + const { setFieldValue, values } = useFormikContext(); + + const selectedFileType = values.exceptions[index]?.fileType; + + const { + data: submitterData, + isLoading: entitiesLoading, + isError: entitiesError, + } = useEntities(); + + const { + data: fetchedCDLData, + isLoading: cdlLoading, + isError: cdlError, + } = useCDLs(selectedFileType); + + useEffect(() => { + if (fetchedCDLData && fetchedCDLData.cdls) { + setCdlData(fetchedCDLData); + } + }, [fetchedCDLData]); + + useEffect(() => { + if (selectedCDL) { + setFieldValue( + `exceptions[${index}].required_threshold`, + selectedCDL?.threshold_value || '' + ); + } + if (!selectedFileType || selectedFileType === '') { + setCdlData(undefined); + setSelectedCDL(undefined); + setFieldValue(`exceptions[${index}].fieldCode`, ''); + setFieldValue(`exceptions[${index}].required_threshold`, ''); + setFieldValue(`exceptions[${index}].requested_threshold`, ''); + } else if (fetchedCDLData && fetchedCDLData.cdls) { + setCdlData(fetchedCDLData); + } + }, [selectedCDL, selectedFileType, setFieldValue, index]); + + if (entitiesLoading) + return ( +
+ +
+ ); + + return ( + <> +
+

Requested Threshold Reduction {index + 1}

+ + {submitterData && ( + <> + + + {submitterData?.submitters?.map((submitter: Entities) => ( + + ))} + + + )} + {entitiesError && ( + + There was an error finding your associated businesses.{' '} + + Please submit a ticket. + + + )} + + + ) => { + setFieldValue(`exceptions[${index}].fileType`, e.target.value); + setFieldValue(`exceptions[${index}].fieldCode`, ''); + }} + > + + + + + + + + + + ) => { + setSelectedCDL( + cdlData?.cdls.find( + (cdl) => cdl.field_list_code === e.target.value + ) + ); + setFieldValue(`exceptions[${index}].fieldCode`, e.target.value); + }} + > + {cdlData ? ( + <> + + {cdlData.cdls.map((cdl: any) => ( + + ))} + + ) : ( + + )} + + +
+ + + + Must be less than the {selectedCDL.threshold_value} required. + ) : ( + <> + This field code does not require an exception submission. +
Please choose another. + + )) + } + > + +
+ + + +
+ + ); +}; diff --git a/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionFormPage.tsx b/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionFormPage.tsx new file mode 100644 index 00000000..caf878f5 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionFormPage.tsx @@ -0,0 +1,484 @@ +import React, { useState, useEffect } from 'react'; +import { Formik, Form, Field, ErrorMessage } from 'formik'; +import * as Yup from 'yup'; +import { Label } from 'reactstrap'; +import styles from './ExceptionForm.module.css'; +import { ExceptionForm } from './'; +import SectionMessage from 'core-components/SectionMessage'; +import { fetchUtil } from 'utils/fetchUtil'; +import { Link } from 'react-router-dom'; +import { Entities, useEntities } from 'hooks/entities'; +import Button from 'core-components/Button'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; + +interface FormValues { + exceptionType: string; + exceptions: { + businessName: number; + fileType: string; + fieldCode: string; + expiration_date: string; + requested_threshold: number; + required_threshold: number; + }[]; + justification: string; + requestorName: string; + requestorEmail: string; + acceptTerms: boolean; + expirationDateOther: string; + otherExceptionBusinessName: string; +} + +export const ExceptionFormPage: React.FC = () => { + const [selectedExceptionType, setSelectedExceptionType] = + useState(''); + const [numberOfExceptionBlocks] = useState(1); + + // Dynamically determines validation schema based on selectedExceptionType state + const baseSchema = { + exceptionType: Yup.string().required(''), + justification: Yup.string() + .max(2000, 'Must be 2000 characters or less') + .required('Justification is required'), + requestorName: Yup.string().required('Requestor name is required'), + requestorEmail: Yup.string() + .email('Invalid email') + .required('Requestor email is required'), + acceptTerms: Yup.boolean().oneOf([true], 'You must accept the terms'), + }; + + const exceptionSchema = Yup.array().of( + Yup.object().shape({ + // Allows users to pick from human readable business names, but passes submitter id to + // database query which is what the table looks for to match exception with submitter + businessName: Yup.number() + .transform((val, original) => + original == '' || isNaN(original) ? undefined : val + ) + .typeError('Business name is required') + .required('Business name is required'), + fileType: Yup.string().required('File type is required'), + fieldCode: Yup.string().required('Field code is required'), + expiration_date: Yup.date() + .required('Expiration date is required') + .max('9999-12-31', 'Expiration date must be MM/DD/YYYY') + .min('0001-01-01', 'Expiration date must be MM/DD/YYYY'), + requested_threshold: Yup.number().required( + 'Requested threshold is required' + ), + required_threshold: Yup.number() + .min(1, 'This field code does not require an exception submission.') + .required('Required'), + }) + ); + + const validationSchema = Yup.object().shape({ + ...baseSchema, + exceptions: Yup.mixed().when('exceptionType', { + is: 'threshold', + then: (schema) => exceptionSchema, + otherwise: (schema) => schema.strip(), + }), + expirationDateOther: Yup.mixed().when('exceptionType', { + is: 'other', + then: (schema) => + Yup.date() + .required('Required') + .max('9999-12-31', 'Date must be MM/DD/YYYY') + .min('0001-01-01', 'Date must be MM/DD/YYYY'), + otherwise: (schema) => schema.strip(), + }), + otherExceptionBusinessName: Yup.mixed().when('exceptionType', { + is: 'other', + then: () => Yup.number().min(1, 'Required').required('Required'), + otherwise: () => Yup.mixed().strip(), + }), + }); + const initialValues: FormValues = { + exceptionType: selectedExceptionType ? selectedExceptionType : '', + exceptions: Array.from({ length: numberOfExceptionBlocks }).map(() => ({ + businessName: 0, + fileType: '', + fieldCode: '', + expiration_date: '', + requested_threshold: 0, + required_threshold: 0, + })), + justification: '', + requestorName: '', + requestorEmail: '', + acceptTerms: false, + expirationDateOther: '', + otherExceptionBusinessName: '', + }; + + const [errorMessage, setErrorMessage] = useState(''); + const [isSuccess, setIsSuccess] = useState(false); + const [lastSubmitCount] = useState(0); + + const { + data: submitterData, + isLoading: entitiesLoading, + isError: entitiesError, + } = useEntities(); + + const handleSubmit = async ( + values: FormValues, + { setSubmitting }: { setSubmitting: (isSubmitting: boolean) => void } + ) => { + setErrorMessage(''); + const url = `submissions/exception/api/`; + try { + const response = await fetchUtil({ + url, + method: `POST`, + body: values, + }); + if (response.status == 'success') { + setIsSuccess(true); + } + } catch (error: any) { + console.error('Error saving data:', error); + console.log(url); + if (error.response && error.response.data) { + setErrorMessage( + error.response.data.message || + 'An error occurred while saving the data. Please try again.' + ); + } else { + setErrorMessage( + 'An error occurred while saving the data. Please try again.' + ); + } + } finally { + setSubmitting(false); + } + }; + + if (entitiesLoading) { + return ( +
+ +
+ ); + } + + const getExceptionTitle = () => { + switch (selectedExceptionType) { + case 'threshold': + return 'Threshold '; + case 'other': + return 'Other '; + default: + return ''; + } + }; + + return ( +
+

{getExceptionTitle()} Exception Request

+
+

+ This form should be completed and submitted only by entities who are + eligible for an exception to certain data submission requirements under + H.B. 2090 (87(R)) and associated regulations. Please review the + legislation and regulation before submitting this form. Links to both + can be found on the {''} + + Texas All-Payor Claims Database website. + +

+
+ + {({ + values, + isSubmitting, + setFieldValue, + resetForm, + isValid, + submitCount, + handleSubmit, + dirty, + }) => { + // To reset values to initial values if the form submits successfully + useEffect(() => { + if (isSuccess) { + resetForm({ values: { ...initialValues } }); + } + }, [isSuccess, resetForm]); + // To display message next to submit if fields are invalid on submit + useEffect(() => { + if (submitCount > lastSubmitCount && !isValid) { + setErrorMessage('All required fields must be valid'); + } + }, [submitCount, isValid, lastSubmitCount, handleSubmit]); + return ( +
+

Select Exception Type

+

+ Please select below if you are requesting an exception for + threshold submission requirements or for an general, other type + of exception. +

{' '} +
+ + ) => { + const selection = e.target.value; + setSelectedExceptionType(selection); + setFieldValue('exceptionType', selection); + setIsSuccess(false); + }} + > + + + + + + {selectedExceptionType !== '' && ( +
+ Note: Your changes will not be saved if you change + the exception type. +
+ )} +
+ {selectedExceptionType == 'threshold' && ( +
+ {values.exceptions.map((exception, index) => ( + + ))} +
+ + +
+
+ )} + {selectedExceptionType === 'other' && ( + <> +
+

Exception Details

+
+ {submitterData && ( + <> + + + + {submitterData?.submitters?.map( + (submitter: Entities) => ( + + ) + )} + + + + )} +
+ {entitiesError && ( + + There was an error finding your associated businesses.{' '} + + Please submit a ticket. + + + )} +
+ + + +
+ + )} + {selectedExceptionType && ( + <> +
+

Request and Justification

+ + + +
+

Acknowledgment of Terms

+ +
+ + + + + + + + + +
+ {isSuccess ? ( + <> + +
+ setIsSuccess(false)} + > + Your exception request was successfully sent. + +
+ + ) : ( + + )} + {errorMessage && ( +
+ + {errorMessage} + +
+ )} +
+
+ + * Exceptions cannot be granted for periods longer than a + year. +
+ ** Exceptions cannot be granted from any requirement in + insurance code Chapter 38. +
+
+
+ + )} +
+ ); + }} +
+
+ ); +}; diff --git a/apcd_cms/src/client/src/components/Submitter/Exceptions/index.ts b/apcd_cms/src/client/src/components/Submitter/Exceptions/index.ts new file mode 100644 index 00000000..185905eb --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Exceptions/index.ts @@ -0,0 +1,4 @@ +import { ExceptionForm } from './ExceptionForm'; +import { ExceptionFormPage } from './ExceptionFormPage'; + +export { ExceptionForm, ExceptionFormPage }; diff --git a/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx b/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx new file mode 100644 index 00000000..b5cb8f6d --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx @@ -0,0 +1,186 @@ +import React, { useState, useEffect } from 'react'; +import { useFormikContext, Field, ErrorMessage } from 'formik'; +import styles from './ExtensionsForm.module.css'; +import { + SubmitterEntityData, + Entities, + ApplicableDataPeriod, +} from 'hooks/entities'; +import SectionMessage from 'core-components/SectionMessage'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; + +const maxDate = new Date(); +maxDate.setFullYear(maxDate.getFullYear() + 1); +const oneYearFromToday = maxDate.toISOString().split('T')[0]; + +const ExtensionFormInfo: React.FC<{ + index: number; + submitterData: SubmitterEntityData | undefined; +}> = ({ index, submitterData }) => { + const [selectedEntity, setSelectedEntity] = useState(); + const [dataPeriods, setDataPeriods] = useState([]); + const { setFieldValue, values } = useFormikContext(); + + useEffect(() => { + if (selectedEntity) { + const entityId = parseInt(selectedEntity, 10); + setFieldValue(`extensions[${index}].currentExpectedDate`, ''); + setFieldValue(`extensions[${index}].applicableDataPeriod`, ''); + setDataPeriods( + submitterData?.submitters.find((s) => s.submitter_id === entityId) + ?.data_periods ?? [] + ); + } else { + setFieldValue(`extensions[${index}].currentExpectedDate`, ''); + setFieldValue(`extensions[${index}].applicableDataPeriod`, ''); + setDataPeriods([]); + } + }, [selectedEntity, index]); + + return ( + <> +
+

Extension Information {index + 1}

+

This extension is on behalf of the following organization:

+ + + {submitterData && ( + <> + ) => { + setSelectedEntity(e.target.value); + setFieldValue( + `extensions[${index}].businessName`, + e.target.value + ); + }} + > + + {submitterData?.submitters?.map((submitter: Entities) => ( + + ))} + + + )} + + {!submitterData && ( + + There was an error finding your associated businesses.{' '} + + Please submit a ticket. + + + )} + + + + + + + + + + + +
Submission Dates
+
+ + Applicable Data Period 1 + + } + required={true} + description="Enter month and year" + > + ) => { + setFieldValue( + `extensions[${index}].applicableDataPeriod`, + e.target.value + ); + setFieldValue( + `extensions[${index}].currentExpectedDate`, + dataPeriods.find((p) => p.data_period === e.target.value) + ?.expected_date + ); + }} + > + + {dataPeriods.map((item) => ( + + ))} + + + + + Requested Target Date 2 + + } + required={true} + className={`position-relative ${styles.dateInputContainer}`} + > + + + + + Current Expected Date 3 + + } + required={false} + className={`position-relative ${styles.dateInputContainer} `} + > + + +
+ + ); +}; + +export default ExtensionFormInfo; diff --git a/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.module.css b/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.module.css new file mode 100644 index 00000000..82d06422 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.module.css @@ -0,0 +1,44 @@ +.isInvalid { + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.dateInputField { + padding-right: 2ch; /* Adjust space for icons or padding */ + min-width: 10ch; /* Minimum width for empty input */ +} + +.dateInputContainer { + display: inline-block; +} + +.loadingField { + display: inline-flex; + justify-content: flex-start; + align-items: center; + height: 100%; + width: 100%; +} +.termsCheckbox input { + position: unset; + margin-left: 0; + margin-right: 2px; +} +.fieldRows { + display: flex; + gap: 5rem; + margin-top: 1rem; + margin-bottom: 1rem; +} +.fieldRows input { + font-size: inherit; +} +.justification { + font-size: unset; +} +.dateInputContainer :is(input):read-only { + border-color: unset; + background-color: #e9ecef; +} diff --git a/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx b/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx new file mode 100644 index 00000000..7860ee08 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx @@ -0,0 +1,330 @@ +import React, { useState, useEffect } from 'react'; +import { Formik, Form, Field, ErrorMessage } from 'formik'; +import * as Yup from 'yup'; +import styles from './ExtensionsForm.module.css'; +import ExtensionFormInfo from './ExtensionFormInfo'; +import { useEntities } from 'hooks/entities'; +import { fetchUtil } from 'utils/fetchUtil'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import SectionMessage from 'core-components/SectionMessage'; +import Button from 'core-components/Button'; +import FieldWrapper from 'core-wrappers/FieldWrapperFormik'; + +const validationSchema = Yup.object().shape({ + extensions: Yup.array().of( + Yup.object().shape({ + businessName: Yup.number() + .transform((val, original) => + original == '' || isNaN(original) ? undefined : val + ) + .typeError('Business name is required') + .required('Business name is required'), + extensionType: Yup.string().required('Extension Type is required'), + applicableDataPeriod: Yup.string().required( + 'Applicable Data Period is required' + ), + requestedTargetDate: Yup.date().required( + 'Requested Target Date is required' + ), + currentExpectedDate: Yup.date(), + }) + ), + requestorName: Yup.string().required('Requestor Name is required'), + requestorEmail: Yup.string() + .email('Invalid email') + .required('Requestor Email is required'), + justification: Yup.string() + .max(2000, '2000 character limit') + .required('Justification is required'), + acceptTerms: Yup.boolean().oneOf([true], 'You must accept the terms'), +}); + +interface FormValues { + extensions: { + businessName: string; + extensionType: string; + applicableDataPeriod: string; + requestedTargetDate: string; + currentExpectedDate: string; + }[]; + requestorName: string; + requestorEmail: string; + justification: string; + acceptTerms: boolean; +} + +const initialValues: FormValues = { + extensions: [ + { + businessName: '', + extensionType: '', + applicableDataPeriod: '', + requestedTargetDate: '', + currentExpectedDate: '', + }, + ], + requestorName: '', + requestorEmail: '', + justification: '', + acceptTerms: false, +}; + +export const ExtensionRequestForm: React.FC = () => { + const [errorMessage, setErrorMessage] = useState(''); + const [isSuccess, setIsSuccess] = useState(false); + + const handleSubmit = async ( + values: FormValues, + { setSubmitting }: { setSubmitting: (isSubmitting: boolean) => void } + ) => { + setErrorMessage(''); + const url = `submissions/extension/api/`; + try { + const response = await fetchUtil({ + url, + method: `POST`, + body: values, + }); + if (response.status == 'success') { + setIsSuccess(true); + } + } catch (error: any) { + console.error('Error saving data:', error); + console.log(url); + if (error.response && error.response.data) { + setErrorMessage( + error.response.data.message || + 'An error occurred while saving the data. Please try again.' + ); + } else { + setErrorMessage( + 'An error occurred while saving the data. Please try again.' + ); + } + } finally { + setSubmitting(false); + } + }; + + const { + data: submitterData, + isLoading: entitiesLoading, + isError: entitiesError, + } = useEntities(); + + if (entitiesLoading) { + return ( +
+ +
+ ); + } + + return ( + <> +

Request Extension

+
+ + {({ values, isSubmitting, setFieldValue, resetForm, dirty }) => { + useEffect(() => { + if (isSuccess) { + resetForm(); + } + }, [isSuccess, resetForm]); + { + return ( + <> +

+ This form should be completed and submitted by data submitters + to request an extension to the deadline for submitting either + a regular submission or a corrected resubmission. Please + review the{' '} + + Data Submission Guide + {' '} + for details about completing and submitting this form, + especially regarding the timeliness of the request. +

+
+ {values.extensions.map((extension, index) => ( + + ))} + {' '} + +
+

Request and Justification

+

+ Provide rationale for the exception request, outlining the + reasons why the organization is unable to comply with the + relevant requirements. Provide as much detail as possible + regarding the exception request, indicating the specific + submission requirements for which relief is being sought. If + applicable, indicate how the organization plans to become + compliant.** +

+ + + +
+

Acknowledgment of Terms

+

+ I understand and acknowledge that the Texas Department of + Insurance (TDI) may review the validity of the information + submitted on this form. +

+
+ + + + + + +
+
+ + + +
+ {isSuccess ? ( + <> + +
+ setIsSuccess(false)} + > + Your extension request was successfully sent. + +
+ + ) : ( + + )} + {errorMessage && ( +
+ + {errorMessage} + +
+ )} +
+ + 1 Applicable data period - month/year in which + claims data was adjudicated. + +
+ + 2 Requested target date - requested + day/month/year by which the data should be received (the + extension date). + +
+ + 3 Current expected date - day/month/year in which + applicable data was expected within the submission window. + + + + ); + } + }} +
+ + ); +}; diff --git a/apcd_cms/src/client/src/components/Submitter/Extensions/index.ts b/apcd_cms/src/client/src/components/Submitter/Extensions/index.ts new file mode 100644 index 00000000..3c7f650e --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Extensions/index.ts @@ -0,0 +1,3 @@ +import { ExtensionRequestForm } from './ExtensionsForm'; + +export { ExtensionRequestForm }; diff --git a/apcd_cms/src/client/src/components/Submitter/Registrations/SubmitterRegistrationList.tsx b/apcd_cms/src/client/src/components/Submitter/Registrations/SubmitterRegistrationList.tsx new file mode 100644 index 00000000..a2283279 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Registrations/SubmitterRegistrationList.tsx @@ -0,0 +1,7 @@ +import React from 'react'; +import { RegistrationList } from 'apcd-components/Registrations/RegistrationList'; +import { useSubmitterRegistrations } from 'hooks/registrations'; + +export const SubmitterRegistrationList: React.FC = () => { + return ; +}; diff --git a/apcd_cms/src/client/src/components/Submitter/Registrations/index.ts b/apcd_cms/src/client/src/components/Submitter/Registrations/index.ts new file mode 100644 index 00000000..3b541ac6 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/Registrations/index.ts @@ -0,0 +1,4 @@ +// index.ts +import { SubmitterRegistrationList } from './SubmitterRegistrationList'; + +export { SubmitterRegistrationList }; diff --git a/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/EditRecordModal.tsx b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/EditRecordModal.tsx new file mode 100644 index 00000000..9a6a0082 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/EditRecordModal.tsx @@ -0,0 +1,236 @@ +import React, { useState } from 'react'; +import { + Modal, + ModalBody, + ModalHeader, + Label, + FormGroup, + Row, + Col, + Alert +} from 'reactstrap'; +import Button from 'core-components/Button'; +import { Formik, Field, Form, ErrorMessage } from 'formik'; +import { fetchUtil } from 'utils/fetchUtil'; +import * as Yup from 'yup'; +import { SubmitterUserRow } from 'hooks/admin'; +import styles from './ViewSubmitterUsers.module.scss'; + +interface EditRecordModalProps { + isOpen: boolean; + toggle: () => void; + user: SubmitterUserRow | null; + onEditSuccess?: (updatedUser: SubmitterUserRow) => void; +} + +const EditRecordModal: React.FC = ({ + isOpen, + toggle, + user, + onEditSuccess, +}) => { + const [showSuccessMessage, setShowSuccessMessage] = useState(false); + const [showErrorMessage, setShowErrorMessage] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + + if (!user) return null; + + const initialValues: SubmitterUserRow = { + ...user, + }; + + const validationSchema = Yup.object({ + user_name: Yup.string().required('Name is required'), + user_email: Yup.string() + .email('Invalid email format') + .required('Email is required'), + }); + + const handleSave = async ( + values: SubmitterUserRow, + { setSubmitting }: { setSubmitting: (isSubmitting: boolean) => void } + ) => { + const { user_number } = values; + const url = `administration/users/${user_number}/`; + try { + setShowSuccessMessage(false); + setShowErrorMessage(false); + const response = await fetchUtil({ + url, + method: 'PUT', + body: values, + }); + + if (onEditSuccess && response) { + onEditSuccess(response); + } + + setShowSuccessMessage(true); + } catch (error: any) { + if (error.response && error.response.data) { + // Use error message from the server response + setErrorMessage( + error.response.data.message || + 'An error occurred while saving the data. Please try again.' + ); + } else { + // Use generic error message + setErrorMessage( + 'An error occurred while saving the data. Please try again.' + ); + } + setShowErrorMessage(true); + } finally { + setSubmitting(false); + } + }; + + const userFields = [ + { label: 'Submitter ID', value: user.submitter_id }, + { label: 'User ID', value: user.user_id }, + { label: 'Name', value: user.user_name }, + { label: 'Email', value: user.user_email }, + { label: 'Entity Organization', value: user.entity_name }, + { label: 'Role', value: user.role_name }, + { label: 'Status', value: user.status }, + { label: 'User Number', value: user.user_number }, + { label: 'Payor Code', value: user.payor_code }, + { label: 'Notes', value: user.notes }, + ]; + + const closeBtn = ( + + ); + + return ( + <> + + + Edit User ID: {user.user_id} for {user.user_name} + + +
+ Edit Selected Submitter User +
+ + {({ isSubmitting }) => ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Success: The user data has been successfully updated. + + + Error: {errorMessage} + + +
+ )} +
+
+
+ {userFields.map((field, index) => ( + + +

{field.label}:

+ + +

{field.value}

+ +
+ ))} +
+
+
+ + ); +}; + +export default EditRecordModal; diff --git a/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewRecordModal.tsx b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewRecordModal.tsx new file mode 100644 index 00000000..cd4ac079 --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewRecordModal.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { Modal, ModalHeader, Row, Col, ModalBody } from 'reactstrap'; +import { SubmitterUserRow } from 'hooks/admin'; +import styles from './ViewSubmitterUsers.module.scss'; +// import { formatDate } from 'utils/dateUtil'; + +interface UserDetailsModalProps { + isOpen: boolean; + toggle: () => void; + user: SubmitterUserRow | null; +} + +const UserDetailsModal: React.FC = ({ + isOpen, + toggle, + user, +}) => { + if (!user) return null; + const closeBtn = ( + + ); + return ( + + + Details for User: {user.user_name} ({user.user_id}) + + + +
+ + + Submitter ID: + + {user.submitter_id} + + + + User ID: + + {user.user_id} + + + + Name: + + {user.user_name} + + + + Email: + + {user.user_email} + + + + Entity Organization: + + {user.entity_name} + + + + Role: + + {user.role_name} + + + + Status: + + {user.status} + + + + User Number: + + {user.user_number} + + + + Payor Code: + + {user.payor_code} + + + + Notes: + + {user.notes ? user.notes : 'None'} + +
+
+
+ ); +}; + +export default UserDetailsModal; diff --git a/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.module.scss b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.module.scss new file mode 100644 index 00000000..1c6ce69a --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.module.scss @@ -0,0 +1,62 @@ +$modal-width: 55%; + +.customModal { + max-width: $modal-width !important; + width: $modal-width; +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; +} + +.customModalTitle { + text-transform: none !important; // Prevent text from being all caps + font-size: 2.5rem; + margin: 0; // Ensure there's no margin +} + +.customLabel { + font-size: 1.5rem; // Adjust the font size as needed +} + +.customSubmitButton { + font-size: 1.5rem; // Increase font size + padding: 0.75rem 1.5rem; // Increase padding +} + +.viewRecord { + font-size: 1.25rem; + line-height: 75%; +} + +.greyRectangle { + background-color: lightgrey; + padding: 1rem; + font-weight: bold; + margin-bottom: 1rem; + border-radius: 0.25rem; +} + +.paginatorContainer { + display: flex; + justify-content: center; /* Centers the child horizontally */ + align-items: center; /* Centers the child vertically */ + height: 100%; /* Adjust as needed */ + padding-top: 20px; +} + +.userkey { + padding-bottom: 0.05em; + padding-right: 0.25em; +} + +.userListing { + padding-left: 0.25em; + padding-right: 0.25em; +} + +.userRow { + padding-bottom: 0.1em; +} diff --git a/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.tsx b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.tsx new file mode 100644 index 00000000..e935ad7c --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.tsx @@ -0,0 +1,222 @@ +import React, { useState } from 'react'; +import { + SubmitterUserRow, + useSubmitterUsers, + useSubmitterUserFilters, +} from 'hooks/admin'; +import ViewRecordModal from './ViewRecordModal'; +import EditRecordModal from './EditRecordModal'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import Paginator from 'core-components/Paginator'; +import styles from './ViewSubmitterUsers.module.scss'; +import { ClearOptionsButton } from 'apcd-components/ClearOptionsButton'; + +export const ViewSubmitterUsers: React.FC = () => { + const header = [ + 'Submitter ID', + 'User ID', + 'User Name', + 'Entity Organization', + 'Role', + 'Status', + 'User Number', + 'Payor Code', + 'Actions', + ]; + + const { + data: filterData, + isLoading: isFilterLoading, + isError: isFilterError, + } = useSubmitterUserFilters(); + + const [status, setStatus] = useState('Active'); + const [org, setOrg] = useState('All'); + const [page, setPage] = useState(1); + + const { + data: submitterUserData, + isLoading, + isError, + refetch, + } = useSubmitterUsers(status, org, page); + + const [viewModalOpen, setViewModalOpen] = useState(false); + const [editModalOpen, setEditModalOpen] = useState(false); + const [selectedUser, setSelectedUser] = useState( + null + ); + const [dropdownValue, setDropdownValue] = useState(''); + + const clearSelections = () => { + setStatus('Active'); + setOrg('All'); + setPage(1); + }; + + // Opens modals based on a selected user + const handleActionChange = ( + event: React.ChangeEvent, + user: SubmitterUserRow + ) => { + const action = event.target.value; + setSelectedUser(user); + setDropdownValue(''); + if (action === 'view') { + setViewModalOpen(true); + setEditModalOpen(false); + } else if (action === 'edit') { + setEditModalOpen(true); + setViewModalOpen(false); + } + }; + + const handlePageChange = (newPage: number) => { + if (newPage >= 1 && newPage <= (submitterUserData?.total_pages ?? 1)) { + setPage(newPage); + } + }; + + const handleEditSuccess = (updatedUser: SubmitterUserRow) => { + // Refresh user data after editing is successful + refetch(); + }; + + const closeModal = () => { + setViewModalOpen(false); + setEditModalOpen(false); + setSelectedUser(null); + }; + + if (isFilterLoading || isLoading) { + return ( +
+ +
+ ); + } + + if (isFilterError || isError) { + return
Error loading data
; + } + + return ( +
+

View Submitter Users

+
+

View all submitter users.

+
+
+
+ {/* Filter by Status */} + + Filter by Status: + + + + {/* Filter by Payor Code */} + + Filter by Payor Code: + + + {status !== 'Active' || org !== 'All' ? ( + + ) : null} +
+
+
+ + + + {header.map((columnName: string, index: number) => ( + + ))} + + + + {submitterUserData?.page && submitterUserData.page.length > 0 ? ( + submitterUserData?.page.map( + (user: SubmitterUserRow, rowIndex: number) => ( + + + + + + + + + + + + ) + ) + ) : ( + + + + )} + +
{columnName}
{user.submitter_id}{user.user_id}{user.user_name}{user.entity_name}{user.role_name}{user.status}{user.user_number}{user.payor_code} + +
+ No Data available +
+
+
+ +
+ {selectedUser && viewModalOpen && ( + + )} + {selectedUser && editModalOpen && ( + + )} +
+ ); +}; + +export default ViewSubmitterUsers; diff --git a/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/index.ts b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/index.ts new file mode 100644 index 00000000..87a95e4e --- /dev/null +++ b/apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/index.ts @@ -0,0 +1,3 @@ +import { ViewSubmitterUsers } from './ViewSubmitterUsers'; + +export { ViewSubmitterUsers }; diff --git a/apcd_cms/src/client/src/core-components/Button/Button.module.css b/apcd_cms/src/client/src/core-components/Button/Button.module.css new file mode 100644 index 00000000..8218b852 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Button/Button.module.css @@ -0,0 +1,9 @@ +.root { + position: relative; +} +.root .loading-over-button { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} diff --git a/apcd_cms/src/client/src/core-components/Button/Button.test.jsx b/apcd_cms/src/client/src/core-components/Button/Button.test.jsx new file mode 100644 index 00000000..194f8994 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Button/Button.test.jsx @@ -0,0 +1,109 @@ +// WARNING: Relies on `Icon` because of `getByRole('img')` +import React from 'react'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; +import Button, * as BTN from './Button'; + +const TEST_TEXT = '…'; +const TEST_TYPE = 'primary'; +const TEST_SIZE = 'medium'; + +function testClassnamesByType(type, size, getByRole, getByTestId) { + const root = getByRole('button'); + const typeClassName = BTN.TYPE_MAP[type]; + const sizeClassName = BTN.SIZE_MAP[size]; + expect(root.className).toMatch('root'); + expect(root.className).toMatch(new RegExp(typeClassName)); + expect(root.className).toMatch(new RegExp(sizeClassName)); + expect(root.textContent).toMatch(TEST_TEXT); +} + +function isPropertyLimitation(type, size) { + let isLimited = false; + + if ( + (type === 'primary' && size === 'small') || + (type !== 'link' && !size) || + (type === 'link' && size) + ) + isLimited = true; + + return isLimited; +} + +describe('Button', () => { + it('uses given text', () => { + const { getByRole } = render(); + expect(getByRole('button').textContent).toEqual(TEST_TEXT); + }); + + describe('icons exist as expected when', () => { + test('only `iconNameBefore` is given', () => { + const { queryByTestId } = render( + + ); + expect(queryByTestId('icon-before')).toBeInTheDocument(); + expect(queryByTestId('icon-after')).not.toBeInTheDocument(); + }); + test('only `iconNameAfter` is given', () => { + const { queryByTestId } = render( + + ); + expect(queryByTestId('icon-before')).not.toBeInTheDocument(); + expect(queryByTestId('icon-after')).toBeInTheDocument(); + }); + test('both `iconNameAfter` and `iconNameBefore` are given', () => { + const { queryByTestId } = render( + + ); + expect(queryByTestId('icon-before')).toBeInTheDocument(); + expect(queryByTestId('icon-after')).toBeInTheDocument(); + }); + }); + + describe('all type & size combinations render accurately', () => { + it.each(BTN.TYPES)('type is "%s"', (type) => { + if (isPropertyLimitation(type, TEST_SIZE)) { + return Promise.resolve(); + } + const { getByRole, getByTestId } = render( + + ); + + testClassnamesByType(type, TEST_SIZE, getByRole, getByTestId); + }); + it.each(BTN.SIZES)('size is "%s"', (size) => { + if (isPropertyLimitation(TEST_TYPE, size)) { + return Promise.resolve(); + } + const { getByRole, getByTestId } = render( + + ); + + testClassnamesByType(TEST_TYPE, size, getByRole, getByTestId); + }); + }); + + describe('loading', () => { + it('does not render button without text', () => { + const { queryByTestId } = render( + + ); + const el = queryByTestId('no button here'); + expect(el).toBeNull(); + }); + it('disables button when in loading state', () => { + const { queryByText } = render( + + ); + const el = queryByText('Loading Button').closest('button'); + expect(el).toBeDisabled(); + }); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/Button/Button.tsx b/apcd_cms/src/client/src/core-components/Button/Button.tsx new file mode 100644 index 00000000..b6faae02 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Button/Button.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import Icon from '../Icon'; +import LoadingSpinner from '../LoadingSpinner'; +import styles from './Button.module.css'; + +export const TYPE_MAP = { + primary: 'primary', + secondary: 'secondary', + tertiary: 'tertiary', + active: 'is-active', + link: 'as-link', +}; + +export const SIZE_MAP = { + short: 'width-short', + medium: 'width-medium', + long: 'width-long', + small: 'size-small', +}; + +export const TYPES = [''].concat(Object.keys(TYPE_MAP)); + +export const SIZES = [''].concat(Object.keys(SIZE_MAP)); + +export const ATTRIBUTES = ['button', 'submit', 'reset']; + +type ButtonTypeLinkSize = { + type?: 'link'; + size?: never; +}; +type ButtonTypeOtherSize = { + type?: 'primary' | 'secondary' | 'tertiary' | 'active'; + size?: 'short' | 'medium' | 'long' | 'small'; +}; + +type ButtonProps = React.PropsWithChildren<{ + className?: string; + iconNameBefore?: string; + iconNameAfter?: string; + id?: string; + dataTestid?: string; + disabled?: boolean; + onClick?: (e: React.MouseEvent) => void; + attr?: 'button' | 'submit' | 'reset'; + isLoading?: boolean; +}> & + (ButtonTypeLinkSize | ButtonTypeOtherSize); + +const Button: React.FC = ({ + children, + className, + iconNameBefore, + iconNameAfter, + id, + type = 'secondary', + size = '', + dataTestid, + disabled, + onClick, + attr = 'button', + isLoading = false, +}) => { + function onclick(e: React.MouseEvent) { + if (disabled) { + e.preventDefault(); + return; + } + if (onClick) { + return onClick(e); + } + } + + return ( + + ); +}; + +export default Button; diff --git a/apcd_cms/src/client/src/core-components/Button/index.ts b/apcd_cms/src/client/src/core-components/Button/index.ts new file mode 100644 index 00000000..803f51fb --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Button/index.ts @@ -0,0 +1,3 @@ +import Button from './Button'; + +export default Button; diff --git a/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.jsx b/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.jsx new file mode 100644 index 00000000..6773a66d --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import Icon from '../Icon'; + +import styles from './Checkbox.module.css'; + +// RFE: Use (and style) an actual checkbox… `` +// and still support `DataFilesListingCells`'s button usage (how?) +// (this would also resolve the aria/lint complications noted below) +const Checkbox = ({ className, isChecked, tabIndex, role, ...props }) => { + const rootStyleNames = [ + styles['root'], + isChecked ? styles['is-checked'] : '', + ].join(' '); + + return ( + + + + + ); +}; +Checkbox.propTypes = { + /** Additional className for the root element */ + className: PropTypes.string, + /** Whether box should be checked */ + isChecked: PropTypes.bool, + /** Standard HTML attribute [tabindex] */ + tabIndex: PropTypes.number, + /** Standard HTML attribute [role] */ + role: PropTypes.string, +}; +Checkbox.defaultProps = { + className: '', + isChecked: false, + tabIndex: 0, + role: 'checkbox', +}; + +export default Checkbox; diff --git a/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.module.css b/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.module.css new file mode 100644 index 00000000..b3007945 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.module.css @@ -0,0 +1,23 @@ +@import url('@tacc/core-styles/dist/settings/color--portal.css'); + +/* HACK: Only necessary because icon sizes are not managed by yet */ +.root, +.root > * { + font-size: 1rem !important; /* override `.icon, .icon-set` */ +} + +/* Children */ + +.check { + background-color: var(--global-color-accent--normal); + color: var(--global-color-primary--xx-light); + + clip-path: inset(0.075em); /* to hide internal padding around box shape */ +} +.root:not(.is-checked) .check { + display: none; +} + +.box { + color: var(--global-color-primary--x-dark); +} diff --git a/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.test.jsx b/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.test.jsx new file mode 100644 index 00000000..6ff12cc9 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Checkbox/Checkbox.test.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import Checkbox from './Checkbox'; + +describe('Icon', () => { + it('has correct `className` (when not passed `isChecked`)', () => { + const { getByRole } = render(); + const el = getByRole('checkbox'); + expect(el.className).not.toMatch(`is-checked`); + }); + it('has correct `className` (when passed `isChecked`)`', () => { + const { getByRole } = render(); + const el = getByRole('checkbox'); + expect(el.className).toMatch(`is-checked`); + }); + it('has correct `role` (when not passed `role`)', () => { + const { getByRole } = render(); + const el = getByRole('checkbox'); + expect(el).not.toEqual(null); + }); + it('has correct `role` (when passed `role`)', () => { + const { getByRole } = render(); + const el = getByRole('button'); + expect(el).not.toEqual(null); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/Checkbox/index.js b/apcd_cms/src/client/src/core-components/Checkbox/index.js new file mode 100644 index 00000000..36fa16d8 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Checkbox/index.js @@ -0,0 +1,3 @@ +import Checkbox from './Checkbox'; + +export default Checkbox; diff --git a/apcd_cms/src/client/src/core-components/Collapse/Collapse.module.css b/apcd_cms/src/client/src/core-components/Collapse/Collapse.module.css new file mode 100644 index 00000000..a6d5edec --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Collapse/Collapse.module.css @@ -0,0 +1,21 @@ +.header { + border-bottom: 1px solid gray; + display: flex; + justify-content: space-between; + margin-bottom: 0.5em; + align-items: center; +} + +.controls { + display: flex; + color: gray; + align-items: center; +} + +.expand { + text-decoration: none !important; +} + +.expand:not:hover { + color: gray !important; +} diff --git a/apcd_cms/src/client/src/core-components/Collapse/Collapse.tsx b/apcd_cms/src/client/src/core-components/Collapse/Collapse.tsx new file mode 100644 index 00000000..bfa82a50 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Collapse/Collapse.tsx @@ -0,0 +1,61 @@ +import React, { useState, useCallback } from 'react'; +import Button from '../Button'; +import { Badge } from 'reactstrap'; +import { Collapse as BootstrapCollapse } from 'reactstrap'; +import Icon from '../Icon'; +import styles from './Collapse.module.css'; + +type CollapseProperties = React.PropsWithChildren<{ + title: string; + note?: string; + open?: boolean; + requiredText?: string; + isCollapsable?: boolean; + className?: string; +}>; + +const Collapse: React.FC = ({ + title, + note, + open, + requiredText, + className, + children, + isCollapsable = true, +}) => { + const [isOpen, setIsOpen] = useState(open ?? false); + const toggle = useCallback(() => { + setIsOpen(!isOpen); + }, [isOpen, setIsOpen]); + + return ( +
+
+
+ {title} + {requiredText && ( + + {requiredText} + + )} +
+
+
{note ?? ''}
+ {isCollapsable && ( + + )} +
+
+ + {children} + +
+ ); +}; + +export default Collapse; diff --git a/apcd_cms/src/client/src/core-components/Collapse/index.ts b/apcd_cms/src/client/src/core-components/Collapse/index.ts new file mode 100644 index 00000000..bccdf23e --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Collapse/index.ts @@ -0,0 +1,3 @@ +import { default as Collapse } from './Collapse'; + +export default Collapse; diff --git a/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.jsx b/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.jsx new file mode 100644 index 00000000..be35792f --- /dev/null +++ b/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.jsx @@ -0,0 +1,77 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { v4 as uuidv4 } from 'uuid'; + +import styles from './DescriptionList.module.css'; + +export const DIRECTION_CLASS_MAP = { + vertical: 'is-vert', + horizontal: 'is-horz', +}; +export const DEFAULT_DIRECTION = 'vertical'; +export const DIRECTIONS = ['', ...Object.keys(DIRECTION_CLASS_MAP)]; + +export const DENSITY_CLASS_MAP = { + compact: 'is-narrow', + default: 'is-wide', +}; +export const DEFAULT_DENSITY = 'default'; +export const DENSITIES = ['', ...Object.keys(DENSITY_CLASS_MAP)]; + +const DescriptionList = ({ className, data, density, direction }) => { + const modifierClasses = []; + modifierClasses.push(DENSITY_CLASS_MAP[density || DEFAULT_DENSITY]); + modifierClasses.push(DIRECTION_CLASS_MAP[direction || DEFAULT_DIRECTION]); + const containerStyleNames = ['container', ...modifierClasses] + .map((s) => styles[s]) + .join(' '); + + const shouldTruncateValues = + (direction === 'vertical' && density === 'compact') || + (direction === 'horizontal' && density === 'default'); + const valueClassName = `${styles.value} ${ + shouldTruncateValues ? 'value-truncated' : '' + }`; + + return ( +
+ {Object.entries(data).map(([key, value]) => ( + +
+ {key} +
+ {Array.isArray(value) ? ( + value.map((val) => ( +
+ {val} +
+ )) + ) : ( +
+ {value} +
+ )} +
+ ))} +
+ ); +}; +DescriptionList.propTypes = { + /** Additional className for the root element */ + className: PropTypes.string, + /** Selector type */ + /* FAQ: We can support any values, even a component */ + // eslint-disable-next-line react/forbid-prop-types + data: PropTypes.object.isRequired, + /** Layout density */ + density: PropTypes.oneOf(DENSITIES), + /** Layout direction */ + direction: PropTypes.oneOf(DIRECTIONS), +}; +DescriptionList.defaultProps = { + className: '', + density: DEFAULT_DENSITY, + direction: DEFAULT_DIRECTION, +}; + +export default DescriptionList; diff --git a/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.module.css b/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.module.css new file mode 100644 index 00000000..394a54be --- /dev/null +++ b/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.module.css @@ -0,0 +1,54 @@ +.container.is-horz, +.container.is-horz dd { + margin-bottom: 0; /* overwrite Bootstrap's `_reboot.scss` */ +} + +/* Children */ + +.key { + composes: x-truncate--one-line from '@tacc/core-styles/dist/tools/x-truncate.css'; +} +.key::after { + content: ':'; + display: inline; + padding-right: 0.25em; +} +.is-horz > .value { + white-space: nowrap; +} + +/* Types */ + +.is-horz { + display: flex; + flex-direction: row; +} +.is-horz > .key ~ .key::before { + content: '|'; + display: inline-block; +} + +.is-horz.is-narrow > .key ~ .key::before { + padding-left: 0.5em; + padding-right: 0.5em; +} +.is-horz.is-wide > .key ~ .key::before { + padding-left: 1em; + padding-right: 1em; +} + +/* Overwrite Bootstrap `_reboot.scss` */ +.is-vert > .value { + margin-left: 0; +} +.is-vert.is-narrow > .value { + padding-left: 0; +} +.is-vert.is-wide > .value { + padding-left: 2.5rem; +} /* 40px Firefox default margin */ + +/* Truncate specific edge cases */ +.value-truncated { + composes: x-truncate--one-line from '@tacc/core-styles/dist/tools/x-truncate.css'; +} diff --git a/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.test.jsx b/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.test.jsx new file mode 100644 index 00000000..e8735ea8 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.test.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import DescriptionList, * as DL from './DescriptionList'; + +const DATA = { + Username: 'bobward500', + Prefix: 'Mr.', + Name: 'Bob Ward', + Suffix: 'The 5th', +}; + +describe('Description List', () => { + it('has accurate tags', async () => { + const { getByTestId, findAllByTestId } = render( + + ); + const list = getByTestId('list'); + const keys = await findAllByTestId('key'); + const values = await findAllByTestId('value'); + expect(list).toBeDefined(); + expect(list.tagName).toEqual('DL'); + keys.forEach((key) => { + expect(key.tagName).toEqual('DT'); + }); + values.forEach((value) => { + expect(value.tagName).toEqual('DD'); + }); + }); + it.each(DL.DIRECTIONS)( + 'has accurate className when direction is "%s"', + (direction) => { + const { getByTestId } = render( + + ); + const list = getByTestId('list'); + const className = + DL.DIRECTION_CLASS_MAP[direction || DL.DEFAULT_DIRECTION]; + expect(list).toBeDefined(); + expect(list.className).toMatch(className); + } + ); + it.each(DL.DENSITIES)( + 'has accurate className when density is "%s"', + (density) => { + const { getByTestId } = render( + + ); + const list = getByTestId('list'); + const className = DL.DENSITY_CLASS_MAP[density || DL.DEFAULT_DENSITY]; + expect(list).toBeDefined(); + expect(list.className).toMatch(className); + } + ); + + it('renders multiple
terms when value is an Array', async () => { + const dataWithArray = { + Hobbits: [ + 'Frodo Baggins', + 'Samwise Gamgee', + 'Meriadoc Brandybuck', + 'Peregrin Took', + ], + }; + const { findAllByTestId } = render( + + ); + const keys = await findAllByTestId('key'); + const values = await findAllByTestId('value'); + expect(keys.length).toEqual(1); + expect(values.length).toEqual(4); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/DescriptionList/index.js b/apcd_cms/src/client/src/core-components/DescriptionList/index.js new file mode 100644 index 00000000..24ce8f7a --- /dev/null +++ b/apcd_cms/src/client/src/core-components/DescriptionList/index.js @@ -0,0 +1,3 @@ +import DescriptionList from './DescriptionList'; + +export default DescriptionList; diff --git a/apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.jsx b/apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.jsx new file mode 100644 index 00000000..8411a981 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Input as BootstrapInput } from 'reactstrap'; + +import styles from './DropdownSelector.module.css'; + +export const TYPES = ['', 'single', 'multiple']; +export const DEFAULT_TYPE = 'single'; + +// RFE: Support `options` object prop and require either `options` or `children` prop: +// - https://stackoverflow.com/a/49682510/11817077 +// - https://stackoverflow.com/a/52661344/11817077 +// - https://www.npmjs.com/package/react-either-property +// - "customProp" at https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes + +const DropdownSelector = ({ type, onChange, ...props }) => { + const canSelectMany = type === 'multiple'; + + return ( + ` is implicit (and depends on `` field (not dropdown) because of browser-limitations */ +/* CREDIT: https://github.com/filamentgroup/select-css/blob/8f91fe1/src/select-css.css */ +/* CAVEAT: Known Issues (across supported browsers): + 1. All: The menus have unique styles per browser and/or operating system. + 2. Safari: The element cascades certain styles (`color`, `font-…`) to menu texts, and they cannot be revert-ed nor initial-ed nor unset. + 3. Firefox: A `width: auto` on the field implies a min-width value equal to the longest `optgroup` (not `option`). + 4. Firefox: Extra horizontal space in field. Options are to hack-a-lot or use a plugin. +*/ +.container { + /* Load select-css after Bootstrap overrides, because Bootstrap is like our "base" */ + composes: form-control from '@tacc/core-styles/dist/components/bootstrap.form.css'; + + /* WARNING: "iOS Safari will [force-zoom site] if […] less than 16px" */ + /* SEE: https://github.com/filamentgroup/select-css#notes-on-the-css */ + width: auto; /* overwrite `.form-control` (from Bootstrap) */ + height: auto; /* overwrite `.form-control` (from Bootstrap) */ + + background-color: var(--global-color-primary--xx-light); + background-image: url("data:image/svg+xml,%3Csvg id='tacc-arrows' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 130.34 292.4'%3E%3Cdefs%3E%3Cstyle%3E.arrow%7Bfill:%23484848;%7D%3C/style%3E%3C/defs%3E%3Cg id='tacc-arrows——root'%3E%3Cpath id='Path_3088' data-name='Path 3088' class='arrow' d='M82.24,96.17,148.09,0l64.45,96.17Z' transform='translate(-82.2)'/%3E%3Cpath id='Path_3089' data-name='Path 3089' class='arrow' d='M212.5,196.23,146.65,292.4,82.2,196.23Z' transform='translate(-82.2)'/%3E%3C/g%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 6px top 50%; /* 5px design * 1.2 design-to-app ratio */ + background-size: auto 10px; /* ~8px design * 1.2 design-to-app ratio (rounded) */ + + color: var(--global-color-accent--normal); + font-style: italic; + font-weight: 500; + + appearance: none; +} +/* NOTE: CSS Modules does not support `.container.form-control`, but these overrides should be isolated */ +.container { + padding: 0 16px 0 6px; /* overwrite `.form-control` (from bootstrap.form.css) */ + /* 0 13.43px 0 5px design * 1.2 design-to-app ratio */ + + border-color: var( + --global-color-primary--dark + ); /* overwrite `.form-control` (from Bootstrap) */ +} + +.container:focus { + /* border-color: var(--global-color-primary--dark); */ + color: var(--global-color-accent--normal); +} +.container[multiple] { + background-image: none; +} + +/* Children */ + +/* Unset styles on children */ +.container option, +.container optgroup { + font-style: normal; + font-weight: normal; +} +.container optgroup { + color: var(--global-color-primary--dark); +} +.container option { + color: var(--global-color-primary--x-dark); +} + +/* FAQ: Ability to style selected option is browser-dependent */ +/* SEE: https://developer.mozilla.org/en-US/docs/Web/CSS/:checked */ +/* .container[multiple] option:checked {} */ diff --git a/apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.test.jsx b/apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.test.jsx new file mode 100644 index 00000000..7f7a361d --- /dev/null +++ b/apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.test.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import DropdownSelector, { TYPES } from './DropdownSelector'; + +describe('Select Dropdown Field', () => { + it.each(TYPES)( + 'has accurate tag and attributes when type is "%s"', + (type) => { + const { getByTestId } = render(); + const root = getByTestId('selector'); + expect(root).toBeDefined(); + expect(root.tagName).toEqual('SELECT'); + if (type === 'multiple') { + expect(root.getAttribute('multiple')).toBe(''); // i.e. true + } else { + expect(root.getAttribute('multiple')).toBe(null); // i.e. false + } + } + ); +}); diff --git a/apcd_cms/src/client/src/core-components/DropdownSelector/index.js b/apcd_cms/src/client/src/core-components/DropdownSelector/index.js new file mode 100644 index 00000000..2895b786 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/DropdownSelector/index.js @@ -0,0 +1,3 @@ +import DropdownSelector from './DropdownSelector'; + +export default DropdownSelector; diff --git a/apcd_cms/src/client/src/core-components/Form/FormField.global.css b/apcd_cms/src/client/src/core-components/Form/FormField.global.css new file mode 100644 index 00000000..75e38538 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Form/FormField.global.css @@ -0,0 +1,14 @@ +.form-field__label { + font-weight: bold; +} + +.form-field__help { + font-style: italic; + font-weight: 400; +} + +.form-field__validation-error { + font-size: 0.8rem; + color: #eb6e6e; + padding-top: 5px; +} diff --git a/apcd_cms/src/client/src/core-components/Form/FormField.jsx b/apcd_cms/src/client/src/core-components/Form/FormField.jsx new file mode 100644 index 00000000..4c55592c --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Form/FormField.jsx @@ -0,0 +1,168 @@ +import React, { useState } from 'react'; +import { + FormGroup, + Label, + Input, + FormText, + Badge, + InputGroup, +} from 'reactstrap'; +import Button from '../Button'; + +import { useField } from 'formik'; +import PropTypes from 'prop-types'; +import './FormField.global.css'; + +/** A limited-choice wrapper for `FormField` */ +const FormFieldWrapper = ({ children, type }) => { + let wrapper; + + switch (type) { + case 'InputGroup': + wrapper = {children}; + break; + + case 'FormGroup': + default: + wrapper = {children}; + } + + return wrapper; +}; +FormFieldWrapper.propTypes = { + /** The content for the wrapper */ + children: PropTypes.node.isRequired, + /** Which wrapper to use */ + type: PropTypes.oneOf(['InputGroup', 'FormGroup', '']), +}; +FormFieldWrapper.defaultProps = { + type: 'FormGroup', +}; + +/** + * A standard form field that supports some customization and presets. + * + * Customizations: + * - providing an `` (can not use with "Agave File Selector") + * + * Presets: + * - Agave File Selector (requires `agaveFile` and `SelectModal`) + */ +const FormField = ({ + addon, + addonType, + label, + description, + required, + agaveFile, + SelectModal, + ...props +}) => { + // useField() returns [formik.getFieldProps(), formik.getFieldMeta()] + // which we can spread on and also replace ErrorMessage entirely. + const [field, meta, helpers] = useField(props); + const [openAgaveFileModal, setOpenAgaveFileModal] = useState(false); + const { id, name } = props; + const hasAddon = addon !== undefined; + const wrapperType = hasAddon ? 'InputGroup' : ''; + + const FieldLabel = () => ( + + ); + const FieldNote = () => ( + + {description} + {meta.touched && meta.error && ( +
{meta.error}
+ )} +
+ ); + + // Allowing ineffectual prop combinations would lead to confusion + if (addon && agaveFile) { + throw new Error( + 'You must not pass `addon` and `agaveFile`, because `agaveFile` triggers its own field add-on' + ); + } + if ((!agaveFile && SelectModal) || (agaveFile && !SelectModal)) { + throw new Error('An `agaveFile` and a `SelectModal` must both be passed'); + } + + return ( + <> + {label && hasAddon ? : null} + + {label && !hasAddon ? : null} + {agaveFile ? ( + <> + { + setOpenAgaveFileModal((prevState) => !prevState); + }} + onSelect={(system, path) => { + helpers.setValue(`agave://${system}${path}`); + }} + /> + + + + + + + ) : ( + <> + {hasAddon && addonType === 'prepend' ? addon : null} + + {hasAddon && addonType === 'append' ? addon : null} + + )} + {!hasAddon ? : null} + + {hasAddon ? : null} + + ); +}; +FormField.propTypes = { + id: PropTypes.string, + name: PropTypes.string, + label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), + description: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), + required: PropTypes.bool, + agaveFile: PropTypes.bool, + SelectModal: PropTypes.func, + /** An [``](https://reactstrap.github.io/components/input-group/) to add */ + addon: PropTypes.node, + /** The [`` `addonType`](https://reactstrap.github.io/components/input-group/) to add */ + addonType: PropTypes.oneOf(['prepend', 'append']), +}; +FormField.defaultProps = { + id: undefined, + name: undefined, + label: undefined, + description: undefined, + required: false, + agaveFile: undefined, + SelectModal: undefined, + addon: undefined, + addonType: undefined, +}; + +export default FormField; diff --git a/apcd_cms/src/client/src/core-components/Form/index.js b/apcd_cms/src/client/src/core-components/Form/index.js new file mode 100644 index 00000000..179491f5 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Form/index.js @@ -0,0 +1 @@ +export { default as FormField } from './FormField'; diff --git a/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.jsx b/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.jsx new file mode 100644 index 00000000..6c81f808 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import PropTypes, { number } from 'prop-types'; +import styles from './HistoryBadge.module.css'; + +const HistoryBadge = ({ unread, disabled }) => { + const rootStyle = disabled ? 'root disabled' : 'root'; + if (unread) { + return ( + + {unread < 1000 ? unread : '999+'} + + ); + } + return null; +}; +HistoryBadge.propTypes = { + unread: number.isRequired, + disabled: PropTypes.bool, +}; + +HistoryBadge.defaultProps = { + disabled: false, +}; + +export default HistoryBadge; diff --git a/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.module.css b/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.module.css new file mode 100644 index 00000000..41dac8b6 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.module.css @@ -0,0 +1,17 @@ +@import url('@tacc/core-styles/dist/settings/color--portal.css'); + +.root { + padding: 0 0.3em; /* buffer retained on 2+ digit badge, without increase on 1 digit badge */ + min-width: 1.3em; /* ~18px design * 1.2 design-to-app ratio (rounded) */ + text-align: center; + font-size: 0.75em; /* ~10px design * 1.2 design-to-app ratio */ + border-radius: 3.6px; + background-color: var(--global-color-accent--normal); + color: rgb(253 241 241); + margin-left: auto; + margin-right: 2em; +} + +.disabled { + background-color: var(--global-color-accent--weak); +} diff --git a/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.test.jsx b/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.test.jsx new file mode 100644 index 00000000..de7aa74e --- /dev/null +++ b/apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.test.jsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; +import HistoryBadge from './HistoryBadge'; + +describe('History Badge', () => { + it('renders the badge if there are unread notifs', () => { + const { getByRole } = render(); + expect(getByRole('status')).toBeDefined(); + expect(getByRole('status')).toHaveTextContent(/1/); + }); + + it('renders jobs', () => { + const { queryByRole } = render(); + expect(queryByRole('status')).toBeNull(); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/HistoryBadge/index.js b/apcd_cms/src/client/src/core-components/HistoryBadge/index.js new file mode 100644 index 00000000..33394516 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/HistoryBadge/index.js @@ -0,0 +1 @@ +export { default } from './HistoryBadge'; diff --git a/apcd_cms/src/client/src/core-components/Icon/Icon.test.jsx b/apcd_cms/src/client/src/core-components/Icon/Icon.test.jsx new file mode 100644 index 00000000..9916e561 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Icon/Icon.test.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Icon from './Icon'; + +const NAME = 'test-icon-name'; +const CLASS = 'test-class-name'; +// const TEXT = 'test-icon-text'; +const LABEL = 'test-icon-label'; + +describe('Icon', () => { + it('has correct `className (when not passed a `className`)`', () => { + const { getByRole } = render(); + const icon = getByRole('img'); + expect(icon.className).toMatch(`icon-${NAME}`); + }); + it('has correct `className` (when passed a `className`)', () => { + const { getByRole } = render(); + const icon = getByRole('img'); + expect(icon.className).toMatch(`icon-${NAME}`); + expect(icon.className).toMatch(CLASS); + }); + it('has correct `tagName`', () => { + const { getByRole } = render(); + const icon = getByRole('img'); + expect(icon.tagName).toEqual('I'); + }); + it('has a label', () => { + const { getByLabelText } = render(); + const label = getByLabelText(LABEL); + expect(label).toBeDefined(); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/Icon/Icon.tsx b/apcd_cms/src/client/src/core-components/Icon/Icon.tsx new file mode 100644 index 00000000..0e117878 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Icon/Icon.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +type sizes = 'xs' | 'sm' | 'md' | 'lg'; + +type IconProps = React.PropsWithChildren<{ + className?: string; + dataTestid?: string; + label?: string; + name: string; + size?: sizes; +}>; + +const Icon: React.FC = ({ + className, + dataTestid, + label, + name, + size, +}) => { + const iconClassName = `icon icon-${name}` + (size ? ` icon-${size}` : ''); + // FAQ: The conditional avoids an extra space in class attribute value + const fullClassName = className + ? [className, iconClassName].join(' ') + : iconClassName; + + return ( + + ); +}; + +export default Icon; diff --git a/apcd_cms/src/client/src/core-components/Icon/index.ts b/apcd_cms/src/client/src/core-components/Icon/index.ts new file mode 100644 index 00000000..311b1a23 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Icon/index.ts @@ -0,0 +1,3 @@ +import Icon from './Icon'; + +export default Icon; diff --git a/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.css b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.css new file mode 100644 index 00000000..7f0a87ba --- /dev/null +++ b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.css @@ -0,0 +1,79 @@ +.InfiniteScrollTable { + --cell-horizontal-padding: 0.35em; /* horizontal cell padding for inter-column buffer */ + + /* To force `width: 100%` to have effect when table is wider than container + (use case is any very narrow table, such as when screen is very narrow) */ + /* FAQ: Table is wider than container when row content is wider than table */ + /* CAVEAT: All tables' column widths must be % values whose sum is 100% */ + /* SEE: https://stackoverflow.com/a/6601257 */ + table-layout: fixed; + + max-height: inherit; /* inherit max-height from parent wrapper */ + + border-collapse: separate; + border-spacing: 0; + + & thead { + user-select: none; + color: var(--global-color-primary--x-dark); + border-bottom: 1px solid #707070; + + & .-sort-asc, + & .sort-desc { + color: var(--global-color-primary--xx-dark); + } + + /* Match horizontal padding of `td` elements in table to align properly */ + & th { + padding-left: var(--cell-horizontal-padding); + padding-right: var(--cell-horizontal-padding); + + border-bottom: 1px solid #707070; + background-color: var(--global-color-background--app); + } + } + + & tbody { + & tr { + & button { + white-space: normal; + } + & link { + white-space: normal; + } + & .-status { + box-sizing: border-box; + } + & .-status td { + padding-top: 0.5em; + padding-bottom: 0.5em; + text-align: center; + } + } + & tr:not(.-status) td { + border-bottom: 1px solid rgb(0 0 0 / 10%); + } + & tr:nth-child(even):not(.-status) { + background-color: rgb(0 0 0 / 3%); + } + & tr:hover:not(.-status) { + background-color: rgb(0 0 0 / 5%); + } + + & tr:not(.-status) td { + vertical-align: middle; + padding: 0.7em var(--cell-horizontal-padding); + margin: auto 0; /* vertically center span content */ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + /* Allow cell width to propogate to common child elements */ + & td > a, + & td > span { + /* Stretch cell content to fit available space */ + /* NOTE: Intentionally ineffectual when elements are `display: inline` */ + width: 100%; + } +} diff --git a/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.jsx b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.jsx new file mode 100644 index 00000000..517d242d --- /dev/null +++ b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.jsx @@ -0,0 +1,137 @@ +import React from 'react'; +import { useTable } from 'react-table'; +import PropTypes from 'prop-types'; +import LoadingSpinner from '../LoadingSpinner'; +import './InfiniteScrollTable.css'; +import styles from './InfiniteScrollTable.module.css'; + +const rowContentPropType = PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + PropTypes.oneOf([React.Fragment]), +]); + +const InfiniteScrollLoadingRow = ({ isLoading }) => { + if (!isLoading) { + return null; + } + return ( + + {/* Ensure cell spans across ALL columns */} + + + + + ); +}; +InfiniteScrollLoadingRow.propTypes = { + isLoading: PropTypes.bool.isRequired, +}; + +const InfiniteScrollNoDataRow = ({ display, noDataText }) => { + if (!display) { + return null; + } + return ( + + {/* Ensure cell spans across ALL columns */} + + {noDataText} + + + ); +}; +InfiniteScrollNoDataRow.propTypes = { + display: PropTypes.bool.isRequired, + noDataText: rowContentPropType.isRequired, +}; + +const InfiniteScrollTable = ({ + tableColumns, + tableData, + onInfiniteScroll, + isLoading, + className, + noDataText, + getRowProps, + columnMemoProps, +}) => { + const columns = React.useMemo( + () => tableColumns, + /* eslint-disable-next-line */ + [tableColumns].concat(columnMemoProps) + ); + const data = React.useMemo(() => tableData, [tableData]); + + const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = + useTable({ columns, data }); + + const onScroll = ({ target }) => { + const bottom = + target.scrollHeight - target.scrollTop === target.clientHeight; + if (bottom && target.scrollTop > 0) { + onInfiniteScroll(tableData.length); + } + }; + + return ( + + + {headerGroups.map((headerGroup) => ( + + {headerGroup.headers.map((column) => ( + + ))} + + ))} + + + {rows.map((row) => { + prepareRow(row); + return ( + + {row.cells.map((cell) => { + return ( + + ); + })} + + ); + })} + + + +
{column.render('Header')}
+ {cell.render('Cell')} +
+ ); +}; + +InfiniteScrollTable.propTypes = { + tableColumns: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + tableData: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + onInfiniteScroll: PropTypes.func, + isLoading: PropTypes.bool, + className: PropTypes.string, + noDataText: rowContentPropType, + getRowProps: PropTypes.func, + columnMemoProps: PropTypes.arrayOf(PropTypes.any), +}; +InfiniteScrollTable.defaultProps = { + onInfiniteScroll: (offset) => null, + isLoading: false, + className: '', + noDataText: '', + getRowProps: (row) => null, + columnMemoProps: [], +}; + +export default InfiniteScrollTable; diff --git a/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.module.css b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.module.css new file mode 100644 index 00000000..06a69348 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.module.css @@ -0,0 +1,3 @@ +.container { + composes: o-fixed-header-table from '@tacc/core-styles/dist/objects/o-fixed-header-table.css'; +} diff --git a/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.test.jsx b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.test.jsx new file mode 100644 index 00000000..31bacca9 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.test.jsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import InfiniteScrollTable from './InfiniteScrollTable'; + +const tableData = [ + { + col1: 'Hello', + col2: 'World', + }, + { + col1: 'react-table', + col2: 'rocks', + }, + { + col1: 'whatever', + col2: 'you want', + }, +]; + +const tableColumns = [ + { + Header: 'Column 1', + accessor: 'col1', // accessor is the "key" in the data + }, + { + Header: 'Column 2', + accessor: 'col2', + }, +]; + +describe('InfiniteScrollTable', () => { + it('renders a table', () => { + const { getByText } = render( + + ); + + expect(getByText(/Hello/)).toBeDefined(); + }); + + it('renders a loading spinner', () => { + const { getByTestId } = render( + + ); + + expect(getByTestId(/loading-spinner/)).toBeDefined(); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/InfiniteScrollTable/index.js b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/index.js new file mode 100644 index 00000000..4b97ee1e --- /dev/null +++ b/apcd_cms/src/client/src/core-components/InfiniteScrollTable/index.js @@ -0,0 +1,3 @@ +import InfiniteScrollTable from './InfiniteScrollTable'; + +export default InfiniteScrollTable; diff --git a/apcd_cms/src/client/src/core-components/InlineMessage/InlineMessage.jsx b/apcd_cms/src/client/src/core-components/InlineMessage/InlineMessage.jsx new file mode 100644 index 00000000..9e156567 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/InlineMessage/InlineMessage.jsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import Message from '../Message'; + +/** + * Show a component-specific event-based message to the user + * @example + * // basic usage + * Task complete. + * @see ../Message + */ +const InlineMessage = (props) => { + // Override default props + const messageProps = { + ...Message.defaultProps, + ...props, + canDismiss: false, + scope: 'inline', + }; + + // Avoid manually syncing 's props + // eslint-disable-next-line react/jsx-props-no-spreading + return ; +}; +InlineMessage.propTypes = Message.propTypes; +InlineMessage.defaultProps = Message.defaultProps; + +export default InlineMessage; diff --git a/apcd_cms/src/client/src/core-components/InlineMessage/index.js b/apcd_cms/src/client/src/core-components/InlineMessage/index.js new file mode 100644 index 00000000..5ac27171 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/InlineMessage/index.js @@ -0,0 +1,3 @@ +import InlineMessage from './InlineMessage'; + +export default InlineMessage; diff --git a/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.global.css b/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.global.css new file mode 100644 index 00000000..40bb11f0 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.global.css @@ -0,0 +1,100 @@ +.loading-icon { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; +} +.loading-icon .inline { + width: 1.5rem; + height: 1.5rem; +} +.loading-icon .section { + width: 4rem; + height: 4rem; +} + +button .loading-icon { + display: inline-flex; + vertical-align: middle; + width: auto; +} + +/* FAQ: Clone missing Bootstrap v5 CSS + - LoadingSpinner uses Reactstrap. TUP-UI installed Reactstrap v9. + - Reactstrap v9 assumes Bootstrap v5, which uses class `visually-hidden`. + - Reactstrap v8 assumes Bootstrap v4, which uses class `sr-only`. +*/ + +/* +Spinner (Bootstrap 5) + +Port only the Bootstrap 5 spinner styles that LoadingSpinner needs in tup-ui. + +- [Reactstrap: Components: Spinners](https://react-bootstrap.github.io/components/spinners/) +- [Bootstrap 5: Components: Spinners](https://getbootstrap.com/docs/5.0/components/spinners/) + +Styleguide Component.Bootstrap5.Spinners +*/ +/* https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.css */ +.spinner-border { + display: inline-block; + width: var(--bs-spinner-width); + height: var(--bs-spinner-height); + vertical-align: var(--bs-spinner-vertical-align); + border-radius: 50%; + -webkit-animation: var(--bs-spinner-animation-speed) linear infinite + var(--bs-spinner-animation-name); + animation: var(--bs-spinner-animation-speed) linear infinite + var(--bs-spinner-animation-name); +} +@-webkit-keyframes spinner-border { + to { + transform: rotate(360deg); + } +} +@keyframes spinner-border { + to { + transform: rotate(360deg); + } +} +.spinner-border { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-border-width: 0.25em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-border; + border: var(--bs-spinner-border-width) solid currentcolor; + border-right-color: transparent; +} +@media (prefers-reduced-motion: reduce) { + .spinner-border { + --bs-spinner-animation-speed: 1.5s; + } +} + +/* +Helpers (Bootstrap 5) + +Port Bootstrap 5 utlities. Known use cases: +- tup-ui reactstrap 9 spinner + +- [Reactstrap: Components: Spinners](https://react-bootstrap.github.io/components/spinners/) +- [Bootstrap 5: Helpers: Visually hidden](https://getbootstrap.com/docs/5.0/helpers/visually-hidden/) + +Styleguide Trumps.Bootstrap5.Helpers +*/ +/* https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.css */ +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} diff --git a/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.test.jsx b/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.test.jsx new file mode 100644 index 00000000..52560df1 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import LoadingSpinner from './LoadingSpinner'; + +describe('Loading Spinner component', () => { + it('should render a spinner', () => { + const { getByTestId, getByText } = render(); + expect(getByTestId(/loading-spinner/)).toBeDefined(); + expect(getByText(/Loading.../)).toBeDefined(); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.tsx b/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.tsx new file mode 100644 index 00000000..1f835a79 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Spinner } from 'reactstrap'; + +import './LoadingSpinner.global.css'; + +type LoadingSpinnerProps = { + placement?: 'inline' | 'section'; + className?: string; +}; + +const LoadingSpinner: React.FC = ({ + placement = 'section', + className, +}) => { + return ( +
+ +
+ ); +}; + +export default LoadingSpinner; diff --git a/apcd_cms/src/client/src/core-components/LoadingSpinner/index.ts b/apcd_cms/src/client/src/core-components/LoadingSpinner/index.ts new file mode 100644 index 00000000..72aa1b3c --- /dev/null +++ b/apcd_cms/src/client/src/core-components/LoadingSpinner/index.ts @@ -0,0 +1,3 @@ +import LoadingSpinner from './LoadingSpinner'; + +export default LoadingSpinner; diff --git a/apcd_cms/src/client/src/core-components/Message/Message.jsx b/apcd_cms/src/client/src/core-components/Message/Message.jsx new file mode 100644 index 00000000..0f466880 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Message/Message.jsx @@ -0,0 +1,205 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Fade } from 'reactstrap'; +import Icon from '../Icon'; + +import styles from './Message.module.css'; + +export const ERROR_TEXT = { + mismatchCanDismissScope: + 'For a <(Section)Message> to use `canDismiss`, `scope` must equal `section`.', + deprecatedType: + 'In a <(Section|Inline)Message> `type="warn"` is deprecated. Use `type="warning"` instead.', + missingScope: + 'A without a `scope` should become an . (If must be used, then explicitely set `scope="inline"`.)', +}; + +export const TYPE_MAP = { + info: { + iconName: 'conversation', + className: 'is-info', + iconText: 'Notice', + }, + success: { + iconName: 'approved-reverse', + className: 'is-success', + iconText: 'Notice', + }, + warning: { + iconName: 'alert', + className: 'is-warn', + iconText: 'Warning', + }, + error: { + iconName: 'alert', + className: 'is-error', + iconText: 'Error', + }, +}; +TYPE_MAP.warn = TYPE_MAP.warning; // FAQ: Deprecated support for `type="warn"` +export const TYPES = Object.keys(TYPE_MAP); + +export const SCOPE_MAP = { + inline: { + className: 'is-scope-inline', + role: 'status', + tagName: 'span', + }, + section: { + className: 'is-scope-section', + role: 'status', + tagName: 'p', + }, + // app: { … } // FAQ: Do not use; instead, use a +}; +export const SCOPES = ['', ...Object.keys(SCOPE_MAP)]; +export const DEFAULT_SCOPE = 'inline'; // FAQ: Historical support for default + +/** + * Show an event-based message to the user + * @example + * // basic usage + * Invalid content. + * @example + * // manage dismissal and visibility + * const [isVisible, setIsVisible] = useState(...); + * + * const onDismiss = useCallback(() => { + * setIsVisible(!isVisible); + * }, [isVisible]); + * + * return ( + * + * Uh oh. + * + * ); + * ... + */ +const Message = ({ + ariaLabel, + children, + className, + dataTestid, + onDismiss, + canDismiss, + isVisible, + tagName, + scope, + type, +}) => { + const typeMap = TYPE_MAP[type]; + const scopeMap = SCOPE_MAP[scope || DEFAULT_SCOPE]; + const { iconName, iconText, className: typeClassName } = typeMap; + const { role, tagName: autoTagName, className: scopeClassName } = scopeMap; + + const hasDismissSupport = scope === 'section'; + + // Manage prop warnings + /* eslint-disable no-console */ + if (canDismiss && !hasDismissSupport) { + // Component will work, except `canDismiss` is ineffectual + console.error(ERROR_TEXT.mismatchCanDismissScope); + } + if (type === 'warn') { + // Component will work, but `warn` is deprecated value + console.info(ERROR_TEXT.deprecatedType); + } + if (!scope) { + // Component will work, but `scope` should be defined + console.info(ERROR_TEXT.missingScope); + } + /* eslint-enable no-console */ + + // Manage class names + const modifierClassNames = []; + modifierClassNames.push(typeClassName); + modifierClassNames.push(scopeClassName); + const containerStyleNames = ['container', ...modifierClassNames] + .map((s) => styles[s]) + .join(' '); + + // Manage disappearance + // FAQ: Design does not want fade, but we still use to manage dismissal + // TODO: Consider replacing with a replication of `unmountOnExit: true` + const shouldFade = false; + const fadeProps = { + ...Fade.defaultProps, + unmountOnExit: true, + baseClass: shouldFade ? Fade.defaultProps.baseClass : '', + timeout: shouldFade ? Fade.defaultProps.timeout : 0, + }; + + return ( + 's default props + // eslint-disable-next-line react/jsx-props-no-spreading + {...fadeProps} + tag={tagName || autoTagName} + className={`${className} ${containerStyleNames}`} + role={role} + in={isVisible} + aria-label={ariaLabel} + data-testid={dataTestid} + > + + + {children} + + {canDismiss && hasDismissSupport ? ( + + ) : null} + + ); +}; +Message.propTypes = { + /** How to label this message for accessibility (via `aria-label`) */ + ariaLabel: PropTypes.string, + /** Whether an action can be dismissed (requires scope equals `section`) */ + canDismiss: PropTypes.bool, + /** Message text (as child node) */ + /* FAQ: We can support any values, even a component */ + children: PropTypes.node.isRequired, // This checks for any render-able value + /** Additional className for the root element */ + className: PropTypes.string, + /** ID for test case element selection */ + dataTestid: PropTypes.string, + /** Whether message is visible (pair with `onDismiss`) */ + isVisible: PropTypes.bool, + /** Action on message dismissal (pair with `isVisible`) */ + onDismiss: PropTypes.func, + /** How to place the message within the layout */ + scope: PropTypes.oneOf(SCOPES), // RFE: Require scope; change all instances + /** Message HTML tag (overwrites tag based on scope) */ + tagName: PropTypes.string, + /** Message type or severity */ + type: PropTypes.oneOf(TYPES).isRequired, +}; +Message.defaultProps = { + ariaLabel: 'message', + className: '', + canDismiss: false, + dataTestid: '', + isVisible: true, + onDismiss: () => null, + scope: '', // RFE: Require scope; remove this line +}; + +export default Message; diff --git a/apcd_cms/src/client/src/core-components/Message/Message.module.css b/apcd_cms/src/client/src/core-components/Message/Message.module.css new file mode 100644 index 00000000..d608da0c --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Message/Message.module.css @@ -0,0 +1,147 @@ +@import url('@tacc/core-styles/dist/settings/border.css'); +@import url('@tacc/core-styles/dist/settings/color--portal.css'); + +/* WARNING: No official design */ +/* FAQ: Styles are a mix of static design and dev design */ +/* SEE: https://confluence.tacc.utexas.edu/x/gYCeBw */ + +/* Root */ + +.container { + /* SEE: "Modifiers" */ + /* --buffer-vert: 0; */ + /* --buffer-horz: 0; */ + + /* Vertically center child elements */ + flex-flow: row; + align-items: start; /* FAQ: Effect visible only if text wraps */ + + padding: var(--buffer-vert) var(--buffer-horz); +} +.is-scope-inline { + --buffer-vert: 0; + --buffer-horz: 0; + + display: inline-flex; +} +.is-scope-section { + --buffer-vert: 0.5em; + --buffer-horz: 1em; + + display: flex; +} +/* HELP: FP-1227: Why is this unset? */ +p.is-scope-section { + margin-top: 0; + margin-bottom: 0; +} + +/* Children */ + +.text a { + white-space: nowrap; +} +.type-icon { + margin-right: 0.25em; /* ~4px */ + margin-top: 0.125em; /* HACK: Align better with 14px–17px sibling font */ +} +.close-button { + margin-left: auto; + /* FAQ: Ignore padding by moving over it */ + transform: translateX(var(--buffer-horz)); + + border: none; + background: transparent; + + appearance: none; + color: #222222; +} +.close-icon { + /* … */ +} + +/* Modifiers */ + +/* Modifiers: Type */ + +/* Design decided icon is not necessary for informational messages */ +.is-info .icon:not(.close-icon) { + display: none; +} + +/* Modifiers: Scope */ + +.is-scope-inline { + &.is-info .icon { + color: var(--global-color-info--dark); + } + &.is-warn .icon { + color: var(--global-color-warning--normal); + } + &.is-error, + &.is-error .icon { + color: var(--global-color-danger--normal); + } + &.is-success .icon { + color: var(--global-color-success--normal); + } +} + +.is-scope-section { + border-width: var(--global-border-width--normal); + border-style: solid; + + /* Children */ + & .type-icon { + margin-right: 1rem; + } + + /* Modifiers */ + &.is-info { + color: var(--global-color-info--dark); + border-color: var(--global-color-info--normal); + background-color: var(--global-color-info--x-light); + & .type-icon { + color: var(--global-color-info--dark); + } + } + &.is-warn { + border-color: var(--global-color-warning--normal); + background-color: var(--global-color-warning--weak); + & .type-icon { + color: var(--global-color-warning--normal); + } + } + &.is-error { + border-color: var(--global-color-danger--normal); + background-color: var(--global-color-danger--weak); + & .type-icon { + color: var(--global-color-danger--normal); + } + } + &.is-success { + border-color: var(--global-color-success--normal); + background-color: var(--global-color-success--weak); + & .type-icon { + color: var(--global-color-success--normal); + } + } +} + +/* Modifiers: Complex */ + +.is-scope-inline { + &.is-error a { + color: var(--global-color-danger--normal); + } + /* Distinguish text and `.wb-link`, and link states default and hover */ + &.is-error a:link { + text-decoration-line: underline; + } + &.is-error a:hover { + text-decoration-style: double; + } + &.is-error a:active { + text-decoration-line: underline overline; + } +} diff --git a/apcd_cms/src/client/src/core-components/Message/Message.test.jsx b/apcd_cms/src/client/src/core-components/Message/Message.test.jsx new file mode 100644 index 00000000..de4864f0 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Message/Message.test.jsx @@ -0,0 +1,146 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import Message, * as MSG from './Message'; +import { vi } from 'vitest'; + +const TEST_CONTENT = '…'; +const TEST_TYPE = 'info'; +const TEST_SCOPE = 'inline'; + +function testClassnamesByType(type, getByRole, getByTestId) { + const root = getByRole('status'); + const icon = getByRole('img'); // WARNING: Relies on `Icon` + const text = getByTestId('text'); + const iconName = MSG.TYPE_MAP[type].iconName; + const modifierClassName = MSG.TYPE_MAP[type].className; + expect(root.className).toMatch('container'); + expect(root.className).toMatch(new RegExp(modifierClassName)); + expect(icon.className).toMatch(iconName); + expect(text.className).toMatch('text'); +} + +describe('Message', () => { + it.each(MSG.TYPES)('has correct text for type %s', (type) => { + if (type === 'warn') console.warn = vi.fn(); // mute deprecation warning + const { getByTestId } = render( + + {TEST_CONTENT} + + ); + expect(getByTestId('text').textContent).toEqual(TEST_CONTENT); + }); + + describe('elements', () => { + test.each(MSG.TYPES)('include icon when type is %s', (type) => { + if (type === 'warn') console.warn = vi.fn(); // mute deprecation warning + const { getByRole } = render( + + {TEST_CONTENT} + + ); + expect(getByRole('img')).toBeDefined(); // WARNING: Relies on `Icon` + }); + test.each(MSG.TYPES)('include text when type is %s', (type) => { + if (type === 'warn') console.warn = vi.fn(); // mute deprecation warning + const { getByTestId } = render( + + {TEST_CONTENT} + + ); + expect(getByTestId('text')).toBeDefined(); + }); + test('include button when message is dismissible', () => { + const { getByRole } = render( + + {TEST_CONTENT} + + ); + expect(getByRole('button')).not.toEqual(null); + }); + }); + + describe('visibility', () => { + test('invisible when `isVisible` is `false`', () => { + const { queryByRole } = render( + + {TEST_CONTENT} + + ); + expect(queryByRole('button')).toBeNull(); + }); + test.todo('visible when `isVisible` changes from `false` to `true`'); + // FAQ: Feature works (manually tested), but unit test is difficult + // it('appears when isVisible changes from true to false', async () => { + // let isVisible = false; + // const { findByRole, queryByRole } = render( + // + // {TEST_CONTENT} + // + // ); + // expect(queryByRole('button')).toBeNull(); + // const button = await findByRole('button'); + // isVisible = true; + // expect(button).toBeDefined(); + // }); + }); + + describe('className', () => { + it.each(MSG.TYPES)('is accurate when type is %s', (type) => { + const { getByRole, getByTestId } = render( + + {TEST_CONTENT} + + ); + + testClassnamesByType(type, getByRole, getByTestId); + }); + it.each(MSG.SCOPES)( + 'has accurate className when scope is "%s"', + (scope) => { + const { getByRole, getByTestId } = render( + + {TEST_CONTENT} + + ); + const root = getByRole('status'); + const modifierClassName = MSG.SCOPE_MAP[scope || MSG.DEFAULT_SCOPE]; + + testClassnamesByType(TEST_TYPE, getByRole, getByTestId); + expect(root.className).toMatch(new RegExp(modifierClassName)); + } + ); + }); + + describe('property limitation', () => { + test('is announced for `canDismiss` and `scope`', () => { + console.error = vi.fn(); + render( + + {TEST_CONTENT} + + ); + expect(console.error).toHaveBeenCalledWith( + MSG.ERROR_TEXT.mismatchCanDismissScope + ); + }); + test('is announced for `type="warn"`', () => { + console.info = vi.fn(); + render( + + {TEST_CONTENT} + + ); + expect(console.info).toHaveBeenCalledWith(MSG.ERROR_TEXT.deprecatedType); + }); + test('is announced for missing `scope` value', () => { + console.info = vi.fn(); + render({TEST_CONTENT}); + expect(console.info).toHaveBeenCalledWith(MSG.ERROR_TEXT.missingScope); + }); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/Message/index.js b/apcd_cms/src/client/src/core-components/Message/index.js new file mode 100644 index 00000000..7b7affb0 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Message/index.js @@ -0,0 +1,3 @@ +import Message from './Message'; + +export default Message; diff --git a/apcd_cms/src/client/src/core-components/Paginator/Paginator.jsx b/apcd_cms/src/client/src/core-components/Paginator/Paginator.jsx new file mode 100644 index 00000000..f94d0a4b --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Paginator/Paginator.jsx @@ -0,0 +1,104 @@ +import React from 'react'; +import Button from '../Button'; +import PropTypes from 'prop-types'; +import styles from './Paginator.module.css'; + +const PaginatorEtc = () => { + return ...; +}; + +const PaginatorPage = ({ number, callback, current }) => { + return ( + + ); +}; + +PaginatorPage.propTypes = { + number: PropTypes.number.isRequired, + callback: PropTypes.func.isRequired, + current: PropTypes.number.isRequired, +}; + +const Paginator = ({ pages, current, callback, spread }) => { + let start, end; + if (pages === 1 || pages === 2) { + end = 0; + start = pages; + } else if (pages > 2 && pages <= spread) { + start = 2; + end = pages - 1; + } else if (pages > spread && current <= 4) { + start = 2; + end = spread - 1; + } else if (pages > spread && current > pages - (spread - 2)) { + start = pages - (spread - 2); + end = pages - 1; + } else { + const delta = Math.floor((spread - 2) / 2); + start = current - delta; + end = current + delta; + } + const middle = end - start + 1; + const middlePages = + middle > 0 + ? Array(middle) + .fill() + .map((_, index) => start + index) + : []; + return ( + + ); +}; + +Paginator.propTypes = { + pages: PropTypes.number.isRequired, + current: PropTypes.number.isRequired, + callback: PropTypes.func.isRequired, + spread: PropTypes.number, // Number of page buttons to show +}; + +Paginator.defaultProps = { + spread: 11, +}; + +export default Paginator; diff --git a/apcd_cms/src/client/src/core-components/Paginator/Paginator.module.css b/apcd_cms/src/client/src/core-components/Paginator/Paginator.module.css new file mode 100644 index 00000000..f1ed7d03 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Paginator/Paginator.module.css @@ -0,0 +1,25 @@ +.root { + composes: c-page-list from '@tacc/core-styles/dist/components/c-page.css'; +} +.endcap { + composes: c-page-end from '@tacc/core-styles/dist/components/c-page.css'; + + /* HELP: Should this be in @tacc/core-styles? */ + margin-inline: 12px; +} + +.etcetera { + composes: c-page-item--etcetera from '@tacc/core-styles/dist/components/c-page.css'; +} + +.page-root { + composes: c-page-item from '@tacc/core-styles/dist/components/c-page.css'; +} + +.page { + composes: c-page-link from '@tacc/core-styles/dist/components/c-page.css'; + composes: c-page-link--always-click from '@tacc/core-styles/dist/components/c-page.css'; + + /* To show `c-page-link--always-click` pseudo elements */ + overflow: visible; /* overwrite } + headerClassName="header-test" + content={

Content

} + contentClassName="content-test" + // sidebar={} + // sidebarClassName="sidebar-test" + messages={ + <> + Message + List + + } + /> + ); + expect(container.getElementsByClassName('root-test').length).toEqual(1); + expect(getByText('Header')).not.toEqual(null); + expect(getByText('Header Actions')).not.toEqual(null); + expect(container.getElementsByClassName('header-test').length).toEqual(1); + expect(getByText('Content')).not.toEqual(null); + expect(container.getElementsByClassName('content-test').length).toEqual( + 1 + ); + // expect(getByText('Sidebar')).not.toEqual(null); + // expect(container.getElementsByClassName('sidebar-test').length).toEqual(1); + expect(container.querySelector(`[class*="messages"]`)).not.toEqual(null); + expect(container.getElementsByClassName('messages-test').length).toEqual( + 1 + ); + }); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/Section/index.js b/apcd_cms/src/client/src/core-components/Section/index.js new file mode 100644 index 00000000..9bd61c33 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Section/index.js @@ -0,0 +1 @@ +export { default } from './Section'; diff --git a/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.jsx b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.jsx new file mode 100644 index 00000000..fd488710 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.jsx @@ -0,0 +1,92 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import styles from './SectionContent.module.css'; +import layoutStyles from './SectionContent.layouts.module.css'; + +/** + * Map of layout names to CSS classes + * @enum {number} + */ +export const LAYOUT_CLASS_MAP = { + /** + * Each child element is a flexible block inside one full-height column + */ + oneColumn: layoutStyles['one-column'], + /** + * Each child element is a panel stacked into two full-height columns + * (on narrow screens, there is only one column) + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Columns + */ + twoColumn: layoutStyles['two-column'], + /** + * Each child element is a panel stacked into two or more full-height columns + * (on short wide screens, there are three equal-width columns) + * (on tall wide screens, there are two equal-width columns) + * (on narrow screens, there is only one column) + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Columns + */ + multiColumn: layoutStyles['multi-column'], +}; +export const DEFAULT_LAYOUT = 'one-column'; +export const LAYOUTS = [...Object.keys(LAYOUT_CLASS_MAP)]; + +/** + * A content panel wrapper that supports: + * + * - lay out panels (based on layout name and panel position) + * - change element tag (like `section` instead of `div`) + * - scroll root element (overflow of panel content is not managed) + * - debug layout (via color-coded panels) + * + * @example + * // features: lay out panels, change tag, allow content scroll, color-coded + * + *
Thing 1
+ *
Thing 2
+ *
Thing 3
+ *
+ */ +function SectionContent({ + className, + children, + layoutName, + shouldScroll, + tagName, +}) { + let styleName = ''; + const styleNameList = [styles['root'], layoutStyles['root']]; + const layoutClass = LAYOUT_CLASS_MAP[layoutName]; + const TagName = tagName; + + if (shouldScroll) styleNameList.push(styles['should-scroll']); + if (layoutClass) styleNameList.push(layoutClass); + + // Do not join inside JSX (otherwise arcane styleName error occurs) + styleName = styleNameList.join(' '); + + return {children}; +} +SectionContent.propTypes = { + /** Any additional className(s) for the root element */ + className: PropTypes.string, + /** Content nodes where each node is a block to be laid out */ + children: PropTypes.node.isRequired, + /** The name of the layout by which to arrange the nodes */ + layoutName: PropTypes.oneOf(LAYOUTS).isRequired, + /** Whether to allow root element to scroll */ + shouldScroll: PropTypes.bool, + /** Override tag of the root element */ + tagName: PropTypes.string, +}; +SectionContent.defaultProps = { + className: '', + shouldScroll: false, + tagName: 'div', +}; + +export default SectionContent; diff --git a/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.layouts.module.css b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.layouts.module.css new file mode 100644 index 00000000..1801d6f0 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.layouts.module.css @@ -0,0 +1,87 @@ +@import url('@tacc/core-styles/src/lib/_imports/tools/media-queries.css'); + +/* Base */ + +.root { + /* FAQ: No styles necessary, but defining class to avoid build error */ +} + +/* Debug */ +/* FAQ: To color-code panels, ucncomment the code in this section */ + +/* Color-code panels to easily track movement of multiple panels */ +/* +.root::before { background-color: dimgray; } +.root > *:nth-child(1) { background-color: deeppink; } +.root > *:nth-child(2) { background-color: deepskyblue; } +.root > *:nth-child(3) { background-color: gold; } +.root > *:nth-child(4) { background-color: springgreen; } +.root::after { background-color: lavender; } +*/ + +/* 1 Column */ + +.one-column { + display: flex; + flex-flow: column nowrap; +} + +/* 2 Columns */ + +/* Always */ +.two-column, +.multi-column { + --vertical-buffer: 40px; +} +.two-column > *, +.multi-column > * { + break-inside: avoid; +} + +/* Narrow */ +@media screen and (--medium-and-below) { + .two-column > *, + .multi-column > * { + margin-bottom: var(--vertical-buffer); + } +} + +/* Wide */ +@media screen and (--medium-and-above) { + .two-column, + .multi-column { + column-gap: 48px; + column-rule: 1px solid rgb(112 112 112 / 25%); + column-fill: auto; + } + .two-column > *:not(:last-child), + .multi-column > *:not(:last-child) { + margin-bottom: var(--vertical-buffer); + } +} + +/* Tall & Wide */ +@media screen and (--short-and-above) and (--medium-and-above) { + .two-column, + .multi-column { + column-count: 2; + } +} + +/* Short & Wide */ +@media screen and (--short-and-below) and (--medium-to-wide) { + .two-column { + column-count: 2; + } +} +@media screen and (--short-and-below) and (--wide-and-above) { + .two-column { + column-count: 2; + } + .multi-column { + column-count: 3; + } +} + +@custom-media --short-and-below (height < 634px); +@custom-media --short-and-above (height >= 634px); diff --git a/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.module.css b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.module.css new file mode 100644 index 00000000..f636e844 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.module.css @@ -0,0 +1,19 @@ +/* Block */ + +.root { + /* … */ +} + +/* Modifiers */ + +/* NOTE: Similar on: SectionContent, SectionTableWrapper */ +.should-scroll { + /* We want to permit vertical scrolling, without forcing it… can we? */ + /* FAQ: Did not set `overflow: auto`, because that would certainly hide negative-margined sidebar links */ + /* CAVEAT: Setting `overflow-y` still hides the negative-margined sidebar links because `overflow-x: visible` (default) is re-intepreted as `auto` */ + /* SEE: https://stackoverflow.com/a/6433475/11817077 */ + overflow-y: auto; +} +.root:not(.should-scroll) { + overflow: hidden; +} diff --git a/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.test.jsx b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.test.jsx new file mode 100644 index 00000000..59d089b8 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionContent/SectionContent.test.jsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import SectionContent, { LAYOUT_CLASS_MAP } from './SectionContent'; + +// Create our own `LAYOUTS`, because component one may include an empty string +const LAYOUTS = [...Object.keys(LAYOUT_CLASS_MAP)]; + +export const PARAMETER_CLASS_MAP = { + shouldScroll: 'should-scroll', +}; +export const PARAMETERS = [...Object.keys(PARAMETER_CLASS_MAP)]; + +describe('SectionContent', () => { + describe('elements', () => { + it('renders all passed children', () => { + const { container } = render( + +
Thing 1
+
Thing 2
+
Thing 3
+
+ ); + const root = container.children[0]; + + expect(root.children.length).toEqual(3); + }); + it('renders custom tag', () => { + const { container } = render( + +
Thing
+
+ ); + const root = container.children[0]; + + expect(root.tagName.toLowerCase()).toEqual('main'); + }); + }); + + describe('parameter class names', () => { + it.each(LAYOUTS)( + 'renders accurate class for layout name "%s"', + (layoutName) => { + const { container } = render( + Thing + ); + const classNameString = LAYOUT_CLASS_MAP[layoutName]; + const classNameList = classNameString.split(' '); + + classNameList.forEach((className) => { + expect( + container.querySelector(`[class*="${className}"]`) + ).not.toEqual(null); + }); + } + ); + + it.each(PARAMETERS)( + 'renders accurate class for boolean parameter "%s"', + (parameter) => { + const parameterObj = { [parameter]: true }; + const { container } = render( + +
Thing
+
+ ); + const className = PARAMETER_CLASS_MAP[parameter]; + + expect(container.querySelector(`[class*="${className}"]`)).not.toEqual( + null + ); + } + ); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/SectionContent/index.js b/apcd_cms/src/client/src/core-components/SectionContent/index.js new file mode 100644 index 00000000..0cece963 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionContent/index.js @@ -0,0 +1,6 @@ +export { + default, + LAYOUTS, + DEFAULT_LAYOUT, + LAYOUT_CLASS_MAP, +} from './SectionContent'; diff --git a/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.jsx b/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.jsx new file mode 100644 index 00000000..0c340d43 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.jsx @@ -0,0 +1,93 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import styles from './SectionHeader.module.css'; + +/** + * A header for a `Section[…]` component + * + * - heading text + * - actions (e.g. links, buttons, form) + * - automatic styles or markup for given context (ex: within a form or a table) + * + * @example + * // a section header with heading text (which happens to be also be a link) + * + * Hyperlinked Name of Section + * + * @example + * // a form header with actions and heading text + * Reset} + * isForForm + * > + * Name of Form + * + * @example + * // a table header with actions and heading text + * } + * isForTable + * > + * Name of Table + * + * @example + * // a list header (a list can be like a table with no column headers) + * Name of List + */ +function SectionHeader({ + actions, + children, + className, + isForForm, + isForTable, + isForList, + isNestedHeader, +}) { + let styleName = ''; + const styleNameList = [styles['root']]; + const HeaderTagName = isNestedHeader ? 'div' : 'header'; + const HeadingTagName = isForForm || isForTable || isForList ? 'h2' : 'h1'; + + if (isForForm) styleNameList.push(styles['for-form']); + if (isForTable) styleNameList.push(styles['for-table']); + if (isForList) styleNameList.push(styles['for-list']); + + // Do not join inside JSX (otherwise arcane styleName error occurs) + styleName = styleNameList.join(' '); + + return ( + + {children && ( + + {children} + + )} + {actions} + + ); +} +SectionHeader.propTypes = { + /** Any actions (buttons, links, forms, etc) */ + actions: PropTypes.node, + /** The text a.k.a. title */ + children: PropTypes.node, + /** Any additional className(s) for the root element */ + className: PropTypes.string, + /** Whether this header is for a form */ + isForForm: PropTypes.bool, + /** Whether this header is for a table */ + isForTable: PropTypes.bool, + /** Whether this header is for a list */ + isForList: PropTypes.bool, +}; +SectionHeader.defaultProps = { + actions: '', + className: '', + children: undefined, + isForForm: false, + isForTable: false, + isForList: false, +}; + +export default SectionHeader; diff --git a/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.module.css b/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.module.css new file mode 100644 index 00000000..6d4498ce --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.module.css @@ -0,0 +1,37 @@ +/* Block */ + +.root { + display: flex; + justify-content: space-between; + align-items: flex-end; + flex-wrap: wrap; + align-content: flex-end; /* preserve alignment of items when wrapped */ + + margin-bottom: 15px; +} +.root:not(.for-form, .for-table, .for-list) { + padding-bottom: 15px; + border-bottom: var(--global-border-width--normal) solid + var(--global-color-primary--dark); +} + +/* Elements */ + +/* Elements: Header Actions */ +.heading ~ * { + max-height: 100%; /* (gently) force oversized elements to fit */ +} +.heading ~ a { + font-weight: var(--bold); +} + +/* Modifiers */ + +.for-form, +.for-list { + /* FAQ: No styles necessary, but defining class to avoid build error */ +} + +.for-table { + border-bottom: none; +} diff --git a/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.test.jsx b/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.test.jsx new file mode 100644 index 00000000..5d494e23 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.test.jsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import SectionHeader from './SectionHeader'; + +export const PARAMETER_CLASS_MAP = { + isForForm: 'for-form', + isForTable: 'for-table', +}; +export const PARAMETERS = [...Object.keys(PARAMETER_CLASS_MAP)]; + +describe('SectionHeader', () => { + describe('elements', () => { + it('renders elements with appropriate roles', () => { + const { getByRole } = render( + Button}> + Heading + + ); + // NOTE: Technically (https://www.w3.org/TR/html-aria/#el-header), within a `
` (from `
`), the `header` should not have a role, but `aria-query` recognizes it as a banner (https://github.com/A11yance/aria-query/pull/59) + expect(getByRole('banner').textContent).toEqual('HeadingButton'); + expect(getByRole('heading').textContent).toEqual('Heading'); + }); + }); + + describe('content and classes', () => { + it('renders all passed content and classes', () => { + const { container, getByText } = render( + Button}> + Heading + + ); + expect(getByText('Heading')).not.toEqual(null); + expect(getByText('Button')).not.toEqual(null); + expect(container.getElementsByClassName('root-test').length).toEqual(1); + }); + it('renders JSX header text', () => { + const { getByText } = render( + + Heading + + ); + expect(getByText('Heading')).not.toEqual(null); + }); + }); + + describe('parameter class names', () => { + it.each(PARAMETERS)( + 'renders accurate class and tag for boolean parameter "%s"', + (parameter) => { + const parameterObj = { [parameter]: true }; + const { container, getByText } = render( + Heading + ); + const className = PARAMETER_CLASS_MAP[parameter]; + + expect(container.querySelector(`[class*="${className}"]`)).not.toEqual( + null + ); + expect(getByText('Heading').tagName.toLowerCase()).toEqual('h2'); + } + ); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/SectionHeader/index.js b/apcd_cms/src/client/src/core-components/SectionHeader/index.js new file mode 100644 index 00000000..96dda554 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionHeader/index.js @@ -0,0 +1 @@ +export { default } from './SectionHeader'; diff --git a/apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.jsx b/apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.jsx new file mode 100644 index 00000000..6e02eca7 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.jsx @@ -0,0 +1,50 @@ +import React, { useState } from 'react'; + +import Message from '../Message'; + +/** + * Show a section/page-specific event-based message to the user + * @example + * // basic usage + * Uh oh. + * @see _common/Message + */ +const SectionMessage = (props) => { + const [isVisible, setIsVisible] = useState(true); + const autoManageVisible = props.canDismiss && props.isVisible === undefined; + const autoManageDismiss = props.canDismiss && props.onDismiss === undefined; + + function onDismiss() { + if (autoManageVisible) { + setIsVisible(!isVisible); + } + if (!autoManageDismiss) { + props.onDismiss(); + } + } + + // Override default props + const messageProps = { + ...Message.defaultProps, + ...props, + scope: 'section', + }; + if (autoManageVisible) { + messageProps.isVisible = isVisible; + } + if (autoManageDismiss) { + messageProps.onDismiss = onDismiss; + } + + // Avoid manually syncing 's props + // eslint-disable-next-line react/jsx-props-no-spreading + return ; +}; +SectionMessage.propTypes = Message.propTypes; +SectionMessage.defaultProps = { + ...Message.defaultProps, + isVisible: undefined, + onDismiss: undefined, +}; + +export default SectionMessage; diff --git a/apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.test.jsx b/apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.test.jsx new file mode 100644 index 00000000..f60669c2 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.test.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { + render, + fireEvent, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import SectionMessage from './SectionMessage'; + +const TEST_CONTENT = '…'; +const TEST_TYPE = 'info'; + +describe('SectionMessage', () => { + describe('visibility', () => { + test('removed when dismissed', async () => { + const { getByRole, queryByRole } = render( + + {TEST_CONTENT} + + ); + fireEvent.click(getByRole('button')); + await waitForElementToBeRemoved(() => queryByRole('button')); + }); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/SectionMessage/index.js b/apcd_cms/src/client/src/core-components/SectionMessage/index.js new file mode 100644 index 00000000..9217d694 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionMessage/index.js @@ -0,0 +1,3 @@ +import SectionMessage from './SectionMessage'; + +export default SectionMessage; diff --git a/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.jsx b/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.jsx new file mode 100644 index 00000000..54f60f4d --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.jsx @@ -0,0 +1,199 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import SectionHeader from '../SectionHeader'; + +import styles from './SectionTableWrapper.module.css'; + +/** + * A wrapper required for any table within a flex box. + * (All `Section[…]` components are flex boxes.) + * + * It supports: + * + * - header (with actions, e.g. links, buttons, form) + * - changing the element tag (like `section` instead of `article`) + * - manual or automatic sub-components (i.e. header) + * + * If your table is within a `Section[…]` component, and does not employ this wrapper, you must manually resolve any layout issues. + * + * @see https://stackoverflow.com/q/41421512/11817077 + * @example + * // wrap a table (no header) (that is a flex item) + * + * + * + * @example + * // wrap a table, prepend a header, apply a className + * Heading} + * > + * + * + * @example + * // automatically build sub-components, with some customization + * + * + * + * @example + * // alternate syntax to automatically build content + * + * } + * + * @example + * // manually build sub-components + * // WARNING: Manually built sub-components styles must be manually styled + * offers auto-built header's layout styles + * + * Dashboard + * + * } + * // The "o-flex-item-table-wrap" (if available) mimics `isFlexItem` + * // CAVEAT: Manually load `.o-flex-item-table-wrap` from TACC/Core-Styles + * manualContent={ + *
+ * + *
+ * } + * /> + * @example + * // manually build content (alternate method) + * // WARNING: Manually built sub-components styles must be manually styled + * + * // The "o-flex-item-table-wrap" (if available) mimics `isFlexItem` + * // CAVEAT: Manually load `.o-flex-item-table-wrap` from TACC/Core-Styles + *
+ * + *
+ *
+ */ +function SectionTableWrapper({ + className, + children, + content, + contentClassName, + contentShouldScroll, + header, + headerActions, + headerClassName, + manualContent, + manualHeader, + tagName, + isFlexItem, +}) { + let styleName = ''; + const styleNameList = [styles['root']]; + const TagName = tagName; + const shouldBuildHeader = header || headerClassName || headerActions; + + if (contentShouldScroll) { + styleNameList.push(styles['should-scroll']); + } + if (!manualContent && isFlexItem) { + styleNameList.push(styles['has-wrap']); + } + + // Do not join inside JSX (otherwise arcane styleName error occurs) + styleName = styleNameList.join(' '); + + // Allowing ineffectual prop combinations would lead to confusion + // (unlike
, prop `contentShouldScroll` IS allowed here) + if (manualContent && (content || contentClassName)) { + throw new Error( + 'When passing `manualContent`, the following props are ineffectual: `content`, `contentClassName`' + ); + } + if (manualHeader && (header || headerClassName || headerActions)) { + throw new Error( + 'When passing `manualHeader`, the following props are ineffectual: `header`, `headerClassName`, `headerActions`' + ); + } + + return ( + + {manualHeader ?? + (shouldBuildHeader && ( + + {header} + + ))} + {manualContent ? ( + <> + {manualContent} + {children} + + ) : ( + // This wrapper is the keystone of this component + // WARNING: When using `manualContent`, user must implement this feature + // FAQ: A table can NOT be a flex item;
wrap is safest solution + // SEE: https://stackoverflow.com/q/41421512/11817077 +
+ {content} + {children} +
+ )} + + ); +} +SectionTableWrapper.propTypes = { + /** Any additional className(s) for the root element */ + className: PropTypes.string, + /** Alternate way to pass `manualContent` and `content` */ + children: PropTypes.node, + /** The table content itself (content wrapper built automatically) */ + /* RFE: Ideally, limit this to one `InfiniteScrollTable` or `OtherTable` */ + /* SEE: https://github.com/facebook/react/issues/2979 */ + content: PropTypes.node, + /** Any additional className(s) for the content element */ + contentClassName: PropTypes.string, + /** Whether to allow content to scroll */ + contentShouldScroll: PropTypes.bool, + /** The table header text (header element built automatically) */ + header: PropTypes.node, + /** Any table actions for the header element */ + headerActions: PropTypes.node, + /** Any additional className(s) for the header element */ + headerClassName: PropTypes.string, + /** The table content (built by user) flag or element */ + /* RFE: Ideally, limit these to one relevant `Section[…]` component */ + /* SEE: https://github.com/facebook/react/issues/2979 */ + manualContent: PropTypes.oneOfType([PropTypes.bool, PropTypes.element]), + /** The section header (built by user) element */ + manualHeader: PropTypes.element, + /** Override tag of the root element */ + tagName: PropTypes.string, + isFlexItem: PropTypes.bool, +}; +SectionTableWrapper.defaultProps = { + children: undefined, + className: '', + content: '', + contentClassName: '', + contentShouldScroll: false, + header: '', + headerActions: '', + headerClassName: '', + manualHeader: undefined, + manualContent: undefined, + tagName: 'article', + isFlexItem: false, +}; + +export default SectionTableWrapper; diff --git a/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.module.css b/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.module.css new file mode 100644 index 00000000..1fc5f9f7 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.module.css @@ -0,0 +1,33 @@ +/* Block */ + +.root { + display: flex; + flex-direction: column; +} + +/* Elements */ + +/* CAVEAT: This is only applied to automatically-built sub-components */ +.header { + flex-shrink: 0; +} + +/* Modifiers */ + +/* Ensure table has height so `.table-wrap` can stretch to fill that height */ +.has-wrap { + flex-grow: 1; +} + +/* NOTE: Similar on: SectionContent, SectionTableWrapper */ +.should-scroll .wrap { + /* We want to permit vertical scrolling, without forcing it */ + /* FAQ: Did not set `overflow: auto`, because that would certainly hide negative-margined sidebar links */ + /* CAVEAT: Setting `overflow-y` still hides the negative-margined sidebar links because `overflow-x: visible` (default) is re-intepreted as `auto` */ + /* SEE: https://stackoverflow.com/a/6433475/11817077 */ + overflow-y: auto; +} +.root:not(.should-scroll) .wrap { + /* We want to disable vertical and horizontal scrolling */ + overflow: hidden; +} diff --git a/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.test.jsx b/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.test.jsx new file mode 100644 index 00000000..91e5ab7d --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.test.jsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import SectionTableWrapper from './SectionTableWrapper'; + +const TABLE_MARKUP = ( + + + + + + +
Table Cell
+); + +export const PARAMETER_CLASS_MAP = { + contentShouldScroll: 'should-scroll', +}; +export const PARAMETERS = [...Object.keys(PARAMETER_CLASS_MAP)]; + +describe('SectionTableWrapper', () => { + describe('elements', () => { + it('renders passed children and header', () => { + const { getByRole } = render( + + {TABLE_MARKUP} + + ); + expect(getByRole('table').textContent).toEqual('Table Cell'); + // NOTE: Technically (https://www.w3.org/TR/html-aria/#el-header), the `header` should not have a role, but `aria-query` recognizes it as a banner (https://github.com/A11yance/aria-query/pull/59) + expect(getByRole('banner').textContent).toEqual('Header'); + expect(getByRole('heading').textContent).toEqual('Header'); + }); + }); + + describe('content and class names', () => { + it('renders all passed content and class names', () => { + const { container, getByText } = render( + Header Actions} + headerClassName="header-test" + > + {TABLE_MARKUP} + + ); + expect(container.getElementsByClassName('root-test').length).toEqual(1); + expect(getByText('Header')).not.toEqual(null); + expect(getByText('Header Actions')).not.toEqual(null); + expect(container.getElementsByClassName('header-test').length).toEqual(1); + }); + it('renders conditional class names', () => { + const { container } = render( + {TABLE_MARKUP} + ); + expect(container.querySelector('[class*="has-wrap"]')).not.toEqual(null); + }); + }); + + describe('parameter class names', () => { + it.each(PARAMETERS)( + 'renders accurate class for boolean parameter "%s"', + (parameter) => { + const parameterObj = { [parameter]: true }; + const { container } = render( + + {TABLE_MARKUP} + + ); + const className = PARAMETER_CLASS_MAP[parameter]; + + expect(container.querySelector(`[class*="${className}"]`)).not.toEqual( + null + ); + } + ); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/SectionTableWrapper/index.js b/apcd_cms/src/client/src/core-components/SectionTableWrapper/index.js new file mode 100644 index 00000000..2a0d97d0 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/SectionTableWrapper/index.js @@ -0,0 +1 @@ +export { default } from './SectionTableWrapper'; diff --git a/apcd_cms/src/client/src/core-components/ShowMore/ShowMore.jsx b/apcd_cms/src/client/src/core-components/ShowMore/ShowMore.jsx new file mode 100644 index 00000000..ff349192 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/ShowMore/ShowMore.jsx @@ -0,0 +1,52 @@ +import React, { useState, useCallback } from 'react'; +// To drop this dependency, use `@tacc/core-styles/.../components/c-show-more` +import { useResizeDetector } from 'react-resize-detector'; +import PropTypes from 'prop-types'; + +import Button from '../Button'; + +import styles from './ShowMore.module.css'; + +const ShowMore = ({ className, children }) => { + const [expanded, setExpanded] = useState(false); + + const toggleCallback = useCallback(() => { + setExpanded(!expanded); + }, [expanded, setExpanded]); + + const { height, ref } = useResizeDetector(); + + const hasOverflow = + ref && ref.current ? ref.current.scrollHeight > height : false; + + return ( + <> + { +
+ {children} +
+ } + {(hasOverflow || expanded) && ( + + )} + + ); +}; + +ShowMore.propTypes = { + className: PropTypes.string, + children: PropTypes.node.isRequired, +}; + +ShowMore.defaultProps = { + className: '', +}; + +export default ShowMore; diff --git a/apcd_cms/src/client/src/core-components/ShowMore/ShowMore.module.css b/apcd_cms/src/client/src/core-components/ShowMore/ShowMore.module.css new file mode 100644 index 00000000..52e42d7a --- /dev/null +++ b/apcd_cms/src/client/src/core-components/ShowMore/ShowMore.module.css @@ -0,0 +1,9 @@ +.clamped { + --lines: 4; + + composes: x-truncate--many-lines from '@tacc/core-styles/dist/tools/x-truncate.css'; +} + +.expanded { + composes: x-untruncate--many-lines from '@tacc/core-styles/dist/tools/x-truncate.css'; +} diff --git a/apcd_cms/src/client/src/core-components/ShowMore/index.js b/apcd_cms/src/client/src/core-components/ShowMore/index.js new file mode 100644 index 00000000..1a73fa00 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/ShowMore/index.js @@ -0,0 +1,3 @@ +import ShowMore from './ShowMore'; + +export default ShowMore; diff --git a/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.jsx b/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.jsx new file mode 100644 index 00000000..5ebe10b9 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.jsx @@ -0,0 +1,85 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { NavLink as RRNavLink } from 'react-router-dom'; +import { Nav, NavItem, NavLink } from 'reactstrap'; +import Icon from '../Icon'; +import styles from './Sidebar.module.css'; + +function isNotEmptyString(props, propName, componentName) { + if (!props[propName] || props[propName].replace(/ /g, '') === '') { + return new Error(`No text passed to ${componentName}. Validation failed.`); + } + return null; +} + +const SidebarItem = ({ to, iconName, label, children, disabled, hidden }) => { + return ( + + + + {label} + {children} + + + ); +}; +SidebarItem.propTypes = { + to: PropTypes.string.isRequired, + iconName: PropTypes.string.isRequired, + label: isNotEmptyString, + children: PropTypes.node, + disabled: PropTypes.bool, + hidden: PropTypes.bool, +}; +SidebarItem.defaultProps = { + children: null, + disabled: false, + hidden: false, +}; + +const Sidebar = ({ sidebarItems, addItems, loading }) => { + return ( + + ); +}; + +Sidebar.propTypes = { + sidebarItems: PropTypes.arrayOf(PropTypes.object).isRequired, + addItems: PropTypes.arrayOf(PropTypes.object), + loading: PropTypes.bool, +}; +Sidebar.defaultProps = { + addItems: [], + loading: false, +}; + +export default Sidebar; diff --git a/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.module.css b/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.module.css new file mode 100644 index 00000000..d6b0cf90 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.module.css @@ -0,0 +1,48 @@ +@import url('@tacc/core-styles/dist/settings/color--portal.css'); + +.root { + --width: 215px; + overflow-y: auto; + flex-wrap: nowrap; /* Overwrite Bootstrap `_nav.scss` style for `.nav` */ + min-width: var(--width); + max-width: var(--width); + width: var(--width); + background: #f4f4f4; + border-right: 1px solid rgb(112 112 112 / 25%); + padding-top: 20px; +} + +/* Elements */ + +.link:global(.nav-link) /* extra specific, to override Bootstrap */ { + display: flex; + align-items: center; +} +.link:is(:link, :visited) { + color: var(--global-color-primary--dark); + font-weight: 500; +} +.link:hover, +.link--active:is(:link, :visited) { + color: var(--global-color-primary--x-dark); /* to pass color contrast test */ + background-color: var(--global-color-accent--weak); +} +.link:active, +.link--active:is(:link, :visited) { + font-weight: 700; +} +.link:global(.disabled) { + color: var(--global-color-primary--light); +} + +/* Elements: Icon & Text */ + +.link > *:first-child /* icon (or text, if icon is missing) */ { + text-indent: 20px; +} +.icon { + padding-right: 20px; +} +.text { + font-size: 0.75em; /* ~20px (16px design * 1.2 design-to-app ratio) */ +} diff --git a/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.test.jsx b/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.test.jsx new file mode 100644 index 00000000..01b26993 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Sidebar/Sidebar.test.jsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Sidebar from './Sidebar'; +import { BrowserRouter } from 'react-router-dom'; + +describe('Sidebar', () => { + it('renders sidebar successfully', () => { + const sidebarItems = [ + { to: 'allocations', iconName: 'allocations', label: 'Allocations' }, + { to: 'history', iconName: 'file', label: 'History' }, + ]; + const { queryByTestId } = render( + + + + ); + const el = queryByTestId('sidebar here'); + expect(el).toBeDefined(); + }); + it('does not render sidebar where one item has no text', () => { + const sidebarItems = [ + { to: 'history', iconName: 'file', label: 'History' }, + { to: 'applications', iconName: 'alert' }, + { to: 'ui-patterns', iconName: 'trash', label: 'UI Patterns' }, + ]; + const { queryByTestId } = render( + + + + ); + const el = queryByTestId('no sidebar here'); + expect(el).toBeNull(); + }); +}); diff --git a/apcd_cms/src/client/src/core-components/Sidebar/index.js b/apcd_cms/src/client/src/core-components/Sidebar/index.js new file mode 100644 index 00000000..006af70c --- /dev/null +++ b/apcd_cms/src/client/src/core-components/Sidebar/index.js @@ -0,0 +1,3 @@ +import Sidebar from './Sidebar'; + +export default Sidebar; diff --git a/apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.module.css b/apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.module.css new file mode 100644 index 00000000..52c8337b --- /dev/null +++ b/apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.module.css @@ -0,0 +1,18 @@ +@import url('@tacc/core-styles/dist/settings/color--portal.css'); + +.copy-button { + /* WARNING: Must match JavaScript `transitionDuration` */ + --transition-duration: 0.15; + + transition: color var(--transition-duration), + background-color var(--transition-duration); +} + +.copy-button.is-copied, +/* FAQ: The pseudo-classes override Bootstrap */ +.copy-button.is-copied:hover, +.copy-button.is-copied:focus, +.copy-button.is-copied:active { + background-color: var(--global-color-success--normal); + color: var(--global-color-primary--xx-light); +} diff --git a/apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.tsx b/apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.tsx new file mode 100644 index 00000000..cd4fd9de --- /dev/null +++ b/apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.tsx @@ -0,0 +1,75 @@ +import React, { useCallback, useState } from 'react'; + +import Button from '../Button'; + +import styles from './TextCopyField.module.css'; + +type TextCopyFieldProps = { + value: string; + placeholder?: string; + className?: string; + id?: string; + buttonClassName?: string; +}; + +const TextCopyField: React.FC = ({ + value, + placeholder, + className, + id, + buttonClassName, +}) => { + /* WARNING: Must match CSS `--transition-duration` */ + const transitionDuration = 0.15; // second(s) + const stateDuration = 1; // second(s) + const stateTimeout = transitionDuration + stateDuration; // second(s) + + const [isCopied, setIsCopied] = useState(false); + + const onCopy = useCallback(() => { + navigator.clipboard.writeText(value); + setIsCopied(true); + + const timeout = setTimeout(() => { + setIsCopied(false); + clearTimeout(timeout); + }, stateTimeout * 1000); + }, [value, setIsCopied, stateTimeout]); + const isEmpty = !value || value.length === 0; + const onChange = (event: React.ChangeEvent) => { + // Swallow keyboard events on the Input control, but + // still allow selecting the text. readOnly property of + // Input is not adequate for this purpose because it + // prevents text selection + event.preventDefault(); + }; + + return ( + <> + + + + ); +}; + +export default TextCopyField; diff --git a/apcd_cms/src/client/src/core-components/TextCopyField/index.js b/apcd_cms/src/client/src/core-components/TextCopyField/index.js new file mode 100644 index 00000000..f41d5ff4 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/TextCopyField/index.js @@ -0,0 +1,3 @@ +import TextCopyField from './TextCopyField'; + +export default TextCopyField; diff --git a/apcd_cms/src/client/src/core-components/index.ts b/apcd_cms/src/client/src/core-components/index.ts new file mode 100644 index 00000000..5a791581 --- /dev/null +++ b/apcd_cms/src/client/src/core-components/index.ts @@ -0,0 +1,20 @@ +export { default as Button } from './Button'; +export { default as Icon } from './Icon'; +export { default as Section } from './Section'; +export { default as SectionHeader } from './SectionHeader'; +export { default as InlineMessage } from './InlineMessage'; +export { default as SectionMessage } from './SectionMessage'; +export { default as LoadingSpinner } from './LoadingSpinner'; +export { default as DescriptionList } from './DescriptionList'; +export { default as Message } from './Message'; +export { default as Paginator } from './Paginator'; +export { default as Pill } from './Pill'; +export { default as DropdownSelector } from './DropdownSelector'; +export { default as ShowMore } from './ShowMore'; +export { default as SectionTableWrapper } from './SectionTableWrapper'; +export { default as InfiniteScrollTable } from './InfiniteScrollTable'; +export { default as Sidebar } from './Sidebar'; +export { default as HistoryBadge } from './HistoryBadge'; +export { default as Collapse } from './Collapse'; +export { default as TextCopyField } from './TextCopyField'; +export * from './Form'; diff --git a/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css b/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css new file mode 100644 index 00000000..cd6e1abf --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css @@ -0,0 +1,14 @@ +.required .badge { + color: white; + font-weight: var(--medium); + + margin-left: 0.5em; + vertical-align: top; +} + +.isInvalid { + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} diff --git a/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx b/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx new file mode 100644 index 00000000..ade523ce --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { ErrorMessage } from 'formik'; +import { Badge, FormGroup } from 'reactstrap'; + +import './FieldWrapperFormik.global.css'; + +export type FieldWrapperProps = { + name: string; + label: React.ReactNode; + required?: boolean; + className?: string; + description?: React.ReactNode; +}; +const FieldWrapper: React.FC> = ({ + name, + label, + required, + description, + className, + children, +}) => { + return ( + + + {children} + + {description &&
{description}
} +
+ ); +}; + +export default FieldWrapper; diff --git a/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts b/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts new file mode 100644 index 00000000..2a646c9f --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts @@ -0,0 +1,2 @@ +import { default as FieldWrapperFormik } from './FieldWrapperFormik'; +export default FieldWrapperFormik; diff --git a/apcd_cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx b/apcd_cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx new file mode 100644 index 00000000..2afc3c98 --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import LoadingSpinner from 'core-components/LoadingSpinner'; +import Message from 'core-components/Message'; + +type QueryWrapperProps = React.PropsWithChildren<{ + isLoading: boolean; + error: Error | null; + className?: string; +}>; + +const QueryWrapper: React.FC = ({ + isLoading, + error, + children, + className = '', +}) => { + if (isLoading) { + return ( +
+ +
+ ); + } + + if (error) { + return ( +
+ + {(error as any).message ?? error} + +
+ ); + } + return
{children}
; +}; + +export default QueryWrapper; diff --git a/apcd_cms/src/client/src/core-wrappers/QueryWrapper/index.ts b/apcd_cms/src/client/src/core-wrappers/QueryWrapper/index.ts new file mode 100644 index 00000000..9217387e --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/QueryWrapper/index.ts @@ -0,0 +1,3 @@ +import { default as QueryWrapper } from './QueryWrapper'; + +export default QueryWrapper; diff --git a/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css b/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css new file mode 100644 index 00000000..d8b5a3a3 --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css @@ -0,0 +1,18 @@ +.wrapper { + display: flex; + flex-direction: row; + align-items: center; +} + +.wrapper > * { + margin-right: 0.5em; +} + +.loading-spinner { + margin-left: 1em; + width: inherit; +} + +.reverse { + flex-direction: row-reverse; +} diff --git a/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.module.css b/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.module.css new file mode 100644 index 00000000..e69de29b diff --git a/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx b/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx new file mode 100644 index 00000000..3b846861 --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { LoadingSpinner, Message } from '@tacc/core-components'; +import styles from './SubmitWrapper.module.css'; + +type SubmitWrapperProps = React.PropsWithChildren<{ + isLoading: boolean; + success: string | undefined; + error: Error | null; + className?: string; + reverse?: boolean; +}>; + +const SubmitWrapper: React.FC = ({ + isLoading, + error, + success, + children, + className = '', + reverse = false, +}) => { + return ( +
+ {children} + {isLoading && ( + + )} + {error ? ( + + {(error as any)?.message ?? error} + + ) : ( + success && ( + + {success} + + ) + )} +
+ ); +}; + +export default SubmitWrapper; diff --git a/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/index.ts b/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/index.ts new file mode 100644 index 00000000..34d5f0f5 --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/SubmitWrapper/index.ts @@ -0,0 +1,3 @@ +import SubmitWrapper from './SubmitWrapper'; + +export default SubmitWrapper; diff --git a/apcd_cms/src/client/src/core-wrappers/index.ts b/apcd_cms/src/client/src/core-wrappers/index.ts new file mode 100644 index 00000000..3913c029 --- /dev/null +++ b/apcd_cms/src/client/src/core-wrappers/index.ts @@ -0,0 +1,3 @@ +export { default as QueryWrapper } from './QueryWrapper'; +export { default as SubmitWrapper } from './SubmitWrapper'; +export { FieldWrapperFormik } from './FieldWrapperFormik'; diff --git a/apcd_cms/src/client/src/hooks/admin/index.ts b/apcd_cms/src/client/src/hooks/admin/index.ts new file mode 100644 index 00000000..ce22d108 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/admin/index.ts @@ -0,0 +1,152 @@ +export type UserRow = { + user_id: string; + user_email: string; + user_name: string; + entity_name: string; + role_name: string; + status: string; + user_number: string; + created_at: string; + updated_at: string; + notes: string; + submitter_id: string; + payor_code: string; +}; + +export type FilterOptions = { + status_options: string[]; + org_options: string[]; + sort_options: string[]; + role_options: string[]; + payor_code_options: string[]; +}; + +export type UserResult = { + selected_status: string; + selected_org: string; + pagination_url_namespaces: string; + page: UserRow[]; + page_num: number; + total_pages: number; +}; + +export type ExtensionRow = { + created: string; + org_name: string; + requestor: string; + type: string; + ext_outcome: string; + ext_status: string; + ext_id: string; + submitter_id: string; + approved_expiration_date: string; + current_expected_date: string; + requested_target_date: string; + applicable_data_period: string; + updated_at: string; + submitter_code: string; + payor_code: string; + requestor_email: string; + explanation_justification: string; + notes: string; +}; + +export type ExtensionResult = { + header: string[]; + status_options: string[]; + org_options: string[]; + selected_status: string; + selected_org: string; + page_num: number; + total_pages: number; + query_str: string; + pagination_url_namespaces: string; + page: ExtensionRow[]; +}; + +export type ExceptionModalContent = { + created_at: string; + entity_name: string; + requestor_name: string; + requestor_email: string; + request_type: string; + status: string; + outcome: string; + data_file_name: string; + field_number: string; + required_threshold: string; + requested_threshold: string; + approved_threshold: string; + requested_expiration_date: string; + approved_expiration_date: string; + explanation_justification: string; + notes: string; + updated_at: string; + exception_id: string; +}; + +export type ExceptionRow = { + created_at: string; + entity_name: string; + requestor_name: string; + request_type: string; + requested_threshold: string; + outcome: string; + status: string; + approved_threshold: string; + approved_expiration_date: string; + notes: string; + exception_id: string; + view_modal_content: ExceptionModalContent; +}; + +export type ExceptionResult = { + header: string[]; + status_options: string[]; + status_modal_options: string[]; + outcome_modal_options: string[]; + org_options: string[]; + selected_status: string; + selected_org: string; + query_str: string; + pagination_url_namespaces: string; + page: ExceptionRow[]; + page_num: number; + total_pages: number; +}; + +export type SubmitterUserRow = { + submitter_id: string; + user_id: string; + user_name: string; + entity_name: string; + role_name: string; + status: string; + user_number: string; + payor_code: string; + user_email: string; + created_at: string; + updated_at: string; + notes: string; + org_name: string; +}; + +export type SubmitterUserResult = { + selected_status: string; + selected_payor_code: string; + pagination_url_namespaces: string; + page: SubmitterUserRow[]; + page_num: number; + total_pages: number; +}; + +export { + useExtensions, + useSubmissions, + useUsers, + useExceptions, + useUserFilters, + useSubmissionFilters, + useSubmitterUsers, + useSubmitterUserFilters, +} from './useAdmin'; diff --git a/apcd_cms/src/client/src/hooks/admin/useAdmin.ts b/apcd_cms/src/client/src/hooks/admin/useAdmin.ts new file mode 100644 index 00000000..b10454b8 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/admin/useAdmin.ts @@ -0,0 +1,187 @@ +import { useQuery, UseQueryResult } from 'react-query'; +import { fetchUtil } from 'utils/fetchUtil'; +import { + ExtensionResult, + UserResult, + ExceptionResult, + FilterOptions, + SubmitterUserResult, +} from '.'; + +import { FileSubmissionResult } from 'hooks/submissions'; + +const getUsers = async (params: any) => { + const url = `/administration/view-users/api/`; + const response = await fetchUtil({ url, params }); + return response.response; +}; + +export const useUsers = ( + status?: string, + org?: string, + page?: number +): UseQueryResult => { + const params: { status?: string; org?: string; page?: number } = { + status, + org, + page, + }; + const query = useQuery(['users', params], () => + getUsers(params) + ) as UseQueryResult; + + return { ...query }; +}; + +const getUsersFilters = async () => { + const url = `/administration/view-users/api/options`; + const response = await fetchUtil({ url }); + return response; +}; + +export const useUserFilters = (): UseQueryResult => { + const query = useQuery(['userfilters'], () => getUsersFilters(), { + staleTime: 5 * 60 * 1000, + cacheTime: 10 * 60 * 1000, + refetchOnWindowFocus: false, + }) as UseQueryResult; + + return { ...query }; +}; + +const getSubmitterUsers = async (params: any) => { + const url = `/administration/view-submitter-users/api/`; + const response = await fetchUtil({ url, params }); + return response.response; +}; + +export const useSubmitterUsers = ( + status?: string, + payor_code?: string, + page?: number +): UseQueryResult => { + const params: { status?: string; payor_code?: string; page?: number } = { + status, + payor_code, + page, + }; + const query = useQuery(['submitterUsers', params], () => + getSubmitterUsers(params) + ) as UseQueryResult; + + return { ...query }; +}; + +const getSubmitterUsersFilters = async () => { + const url = `/administration/view-submitter-users/api/options`; + const response = await fetchUtil({ url }); + return response; +}; + +export const useSubmitterUserFilters = (): UseQueryResult => { + const query = useQuery( + ['submitteruserfilters'], + () => getSubmitterUsersFilters(), + { + staleTime: 5 * 60 * 1000, + cacheTime: 10 * 60 * 1000, + refetchOnWindowFocus: false, + } + ) as UseQueryResult; + + return { ...query }; +}; + +const getSubmissionFilters = async () => { + const url = 'administration/list-submissions/api/options'; + const response = await fetchUtil({ url }); + return response; +}; + +export const useSubmissionFilters = (): UseQueryResult => { + const query = useQuery(['submissionFilters'], () => getSubmissionFilters(), { + staleTime: 5 * 60 * 1000, + cacheTime: 10 * 60 * 1000, + refetchOnWindowFocus: false, + }) as UseQueryResult; + + return { ...query }; +}; + +const getSubmissions = async (params: any) => { + const url = `administration/list-submissions/api/`; + const response = await fetchUtil({ + url, + params, + }); + return response.response; +}; + +export const useSubmissions = ( + status?: string, + sort?: string, + page?: number +): UseQueryResult => { + const params: { status?: string; sort?: string; page?: number } = { + status, + sort, + page, + }; + const query = useQuery(['submissions', params], () => + getSubmissions(params) + ) as UseQueryResult; + + return { ...query }; +}; + +const getExtensions = async (params: any) => { + const url = `administration/list-extensions/api/`; + const response = await fetchUtil({ + url, + params, + }); + return response.response; +}; + +export const useExtensions = ( + status?: string, + org?: string, + page?: number +): UseQueryResult => { + const params: { status?: string; org?: string; page?: number } = { + status, + org, + page, + }; + const query = useQuery(['extensions', params], () => + getExtensions(params) + ) as UseQueryResult; + + return { ...query }; +}; + +const getExceptions = async (params: any) => { + const url = `administration/list-exceptions/api/`; + const response = await fetchUtil({ + url, + params, + }); + return response.response; +}; + +export const useExceptions = ( + status?: string, + org?: string, + page?: number +): UseQueryResult => { + const params: { status?: string; org?: string; page?: number } = { + status, + org, + page, + }; + const query = useQuery(['exceptions', params], () => + getExceptions(params) + ) as UseQueryResult; + + return { ...query }; +}; diff --git a/apcd_cms/src/client/src/hooks/cdls/index.ts b/apcd_cms/src/client/src/hooks/cdls/index.ts new file mode 100644 index 00000000..b7f13415 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/cdls/index.ts @@ -0,0 +1,11 @@ +export type cdl = { + field_list_code: string; + field_list_value: string; + threshold_value: number; +}; + +export type cdlObject = { + cdls: cdl[]; +}; + +export { useCDLs } from './useCDLs'; diff --git a/apcd_cms/src/client/src/hooks/cdls/useCDLs.ts b/apcd_cms/src/client/src/hooks/cdls/useCDLs.ts new file mode 100644 index 00000000..22c57413 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/cdls/useCDLs.ts @@ -0,0 +1,21 @@ +import { useQuery, UseQueryResult } from 'react-query'; +import { fetchUtil } from 'utils/fetchUtil'; +import { cdlObject } from '.'; + +const getCDLS = async (file_type: string | undefined) => { + const url = `common_api/cdls/${file_type}`; + const response = await fetchUtil({ + url, + }); + return response; +}; + +export const useCDLs = ( + file_type: string | undefined +): UseQueryResult => { + const query = useQuery(['cdls', file_type], () => getCDLS(file_type), { + enabled: !!file_type, + }) as UseQueryResult; + + return { ...query }; +}; diff --git a/apcd_cms/src/client/src/hooks/entities/index.ts b/apcd_cms/src/client/src/hooks/entities/index.ts new file mode 100644 index 00000000..ece03725 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/entities/index.ts @@ -0,0 +1,23 @@ +export type SubmitterEntityData = { + submitters: Entities[]; +}; + +export type Entities = { + submitter_id: number; + submitter_code: string; + payor_code: number; + user_id: string; + entity_name: string; + data_periods: ApplicableDataPeriod[]; +}; + +export type ApplicableDataPeriod = { + data_period: string; + expected_date: string; +}; + +export type SubmitterDataPeriods = { + data_periods: ApplicableDataPeriod[]; +}; + +export { useEntities, useSubmitterDataPeriods } from './useEntities'; diff --git a/apcd_cms/src/client/src/hooks/entities/useEntities.ts b/apcd_cms/src/client/src/hooks/entities/useEntities.ts new file mode 100644 index 00000000..e726c886 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/entities/useEntities.ts @@ -0,0 +1,40 @@ +import { useQuery, UseQueryResult } from 'react-query'; +import { fetchUtil } from 'utils/fetchUtil'; +import { SubmitterEntityData, SubmitterDataPeriods } from '.'; + +const getEntities = async () => { + const url = `common_api/entities/`; + const response = await fetchUtil({ + url, + }); + return response.response; +}; + +export const useEntities = (): UseQueryResult => { + const query = useQuery(['entities'], () => + getEntities() + ) as UseQueryResult; + + return { ...query }; +}; + +const getSubmitterDataPeriods = async (params: any) => { + const url = `common_api/data_periods/`; + const response = await fetchUtil({ url, params }); + return response.response; +}; + +export const useSubmitterDataPeriods = ( + submitter_id: string | undefined +): UseQueryResult => { + const params: { submitter_id?: string } = { submitter_id }; + const query = useQuery( + ['submitterDataPeriods'], + () => getSubmitterDataPeriods(params), + { + enabled: submitter_id !== undefined && submitter_id !== null, // Allow `0` as valid + } + ) as UseQueryResult; + + return { ...query }; +}; diff --git a/apcd_cms/src/client/src/hooks/registrations/index.ts b/apcd_cms/src/client/src/hooks/registrations/index.ts new file mode 100644 index 00000000..1d8d1237 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/registrations/index.ts @@ -0,0 +1,169 @@ +export type RegFormData = { + registration_data: RegistrationContent; + renew: boolean; +}; + +export { useRegFormData, usePostRegistration } from './useForm'; + +export type StringMap = { + [key: string]: boolean; +}; + +export type RegistrationEntity = { + claim_val: string; + ent_id: number; + claim_and_enc_vol: string; + license: string | null | undefined; + naic: string | null | undefined; + no_covered: number; + ent_name: string; + fein: string | null | undefined; + plans_type: StringMap; + files_type: StringMap; +}; + +export type RegistrationContact = { + cont_id: number; + notif: string; + role: string; + name: string; + phone: string; + email: string; +}; + +export type RegistrationContent = { + reg_id: number; + biz_name: string; + type: string | null | undefined; + city: string; + state: string; + address: string; + zip: number; + for_self: string | null | undefined; + year: number; + status: string; + entities: RegistrationEntity[]; + contacts: RegistrationContact[]; + org_types: StringMap; + us_state_list: string[]; +}; + +export type RegistrationRow = { + biz_name: string; + year: string; + type: string; + location: string; + reg_status: string; + reg_id: number; +}; + +export type RegistrationResult = { + header: string[]; + status_options: string[]; + org_options: string[]; + selected_status: string; + selected_org: string; + query_str: string; + pagination_url_namespaces: string; + page: RegistrationRow[]; + page_num: number; + total_pages: number; +}; + +export type RegistrationFormValues = { + on_behalf_of: string; + reg_year: string; + type: string; + business_name: string; + mailing_address: string; + city: string; + state: string; + zip_code: string; + reg_id?: number; + reg_status?: string; + entities: { + entity_name: string; + fein: string; + license_number: string; + naic_company_code: string; + types_of_plans_commercial: boolean; + types_of_plans_medicare: boolean; + types_of_plans_medicaid: boolean; + types_of_plans_hidden?: boolean; + types_of_files_eligibility_enrollment: boolean; + types_of_files_provider: boolean; + types_of_files_medical: boolean; + types_of_files_pharmacy: boolean; + types_of_files_dental: boolean; + types_of_files_hidden?: boolean; + total_covered_lives: any; + claims_encounters_volume: any; + total_claims_value: any; + entity_id?: number; + }[]; + contacts: { + contact_type: string; + contact_name: string; + contact_phone: string; + contact_email: string; + contact_notifications: boolean; + contact_id?: number; + }[]; +}; + +export function transformToRegistrationFormValues( + registration: RegistrationContent, + renew?: boolean | undefined +): RegistrationFormValues { + const typeValueMap: Record = { + // to set database value for field rather than display value + 'Insurance Carrier': 'carrier', + 'Plan Administrator¹ (TPA/ASO)': 'tpa_aso', + 'Pharmacy Benefit Manager (PBM)': 'pbm', + }; + return { + on_behalf_of: registration.for_self?.toString() ?? '', + reg_year: (registration.year + (renew ? 1 : 0)).toString(), + type: registration.type ? typeValueMap[registration.type] : '', + business_name: registration.biz_name, + mailing_address: registration.address, + city: registration.city, + state: registration.state as string, + zip_code: registration.zip.toString(), + reg_id: registration.reg_id, + reg_status: registration.status, + entities: registration.entities.map((entity) => ({ + entity_name: entity.ent_name, + fein: entity.fein ?? '', + license_number: entity.license ?? '', + naic_company_code: entity.naic ?? '', + types_of_plans_commercial: entity.plans_type['Commercial'], + types_of_plans_medicare: entity.plans_type['Medicare'], + types_of_plans_medicaid: entity.plans_type['Medicaid'], + types_of_files_eligibility_enrollment: + entity.files_type['Eligibility/Enrollment'], + types_of_files_provider: entity.files_type['Provider'], + types_of_files_medical: entity.files_type['Medical'], + types_of_files_pharmacy: entity.files_type['Pharmacy'], + types_of_files_dental: entity.files_type['Dental'], + total_covered_lives: entity.no_covered, + claims_encounters_volume: entity.claim_and_enc_vol, + total_claims_value: entity.claim_val, + entity_id: entity.ent_id, + })), + contacts: registration.contacts.map((contact) => ({ + contact_type: contact.role, + contact_name: contact.name, + contact_phone: contact.phone, + contact_email: contact.email, + contact_notifications: contact.notif ? true : false, + contact_id: contact.cont_id, + })), + }; +} + +export { + useAdminRegistrations, + useSubmitterRegistrations, + useAdminRegistration, +} from './useRegistrations'; diff --git a/apcd_cms/src/client/src/hooks/registrations/useForm.ts b/apcd_cms/src/client/src/hooks/registrations/useForm.ts new file mode 100644 index 00000000..ef915b5c --- /dev/null +++ b/apcd_cms/src/client/src/hooks/registrations/useForm.ts @@ -0,0 +1,66 @@ +import { + useMutation, + useQuery, + useQueryClient, + UseQueryResult, +} from 'react-query'; +import { fetchUtil } from 'utils/fetchUtil'; +import { RegFormData, RegistrationFormValues, RegistrationContent } from '.'; + +const getRegFormData = async (reg_id: string | null) => { + const url = `register/request-to-submit/api/?reg_id=${reg_id}/`; + const response = await fetchUtil({ + url, + }); + return response.response; +}; + +export const useRegFormData = ( + reg_id: string | null +): UseQueryResult => { + const query = useQuery(['reg_form', reg_id], () => getRegFormData(reg_id), { + enabled: !!reg_id, + }) as UseQueryResult; + + return { ...query }; +}; + +const postRegistration = async (url: string, body: RegistrationFormValues) => { + const response = await fetchUtil({ + url, + method: `POST`, + body: body, + }); + return response; +}; + +export function usePostRegistration() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ + url, + body, + }: { + url: string; + body: RegistrationFormValues; + }) => { + return postRegistration(url, body); + }, + onError: (err: Error) => { + console.log(err); + }, + onSuccess: () => { + const keysToInvalidate = [ + 'admin-registration', + 'admin-registrations', + 'submitter-registrations', + ]; + keysToInvalidate.forEach((key) => { + queryClient.invalidateQueries({ + queryKey: [key], + exact: false, // we do not know the parameters, so all keys are invalidated + }); + }); + }, + }); +} diff --git a/apcd_cms/src/client/src/hooks/registrations/useRegistrations.ts b/apcd_cms/src/client/src/hooks/registrations/useRegistrations.ts new file mode 100644 index 00000000..54bc0037 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/registrations/useRegistrations.ts @@ -0,0 +1,61 @@ +import { useQuery, UseQueryResult } from 'react-query'; +import { fetchUtil } from 'utils/fetchUtil'; +import { RegistrationResult, RegistrationContent } from '.'; + +const getAdminRegistrations = async (params: any) => { + const url = `/administration/list-registration-requests/api/`; + const response = await fetchUtil({ url, params }); + return response.response; +}; + +export const useAdminRegistrations = ( + status?: string, + org?: string, + page?: number +): UseQueryResult => { + const params: { status?: string; org?: string; page?: number } = { + status, + org, + page, + }; + const query = useQuery(['admin-registrations', params], () => + getAdminRegistrations(params) + ) as UseQueryResult; + + return { ...query }; +}; + +const getSubmitterRegistrations = async (params: any) => { + const url = `/register/list-registration-requests/api/`; + const response = await fetchUtil({ url, params }); + return response.response; +}; + +export const useSubmitterRegistrations = ( + status?: string, + org?: string, + page?: number +): UseQueryResult => { + const params: { status?: string; org?: string; page?: number } = { + status, + org, + page, + }; + const query = useQuery(['submitter-registrations', params], () => + getSubmitterRegistrations(params) + ) as UseQueryResult; + + return { ...query }; +}; + +export const useAdminRegistration = ( + reg_id: number +): UseQueryResult => { + const params: { reg_id: number } = { + reg_id, + }; + const query = useQuery(['admin-registration', params], () => + getAdminRegistrations(params) + ) as UseQueryResult; + return { ...query }; +}; diff --git a/apcd_cms/src/client/src/hooks/submissions/index.ts b/apcd_cms/src/client/src/hooks/submissions/index.ts new file mode 100644 index 00000000..3d0b6819 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/submissions/index.ts @@ -0,0 +1,40 @@ +export type StringMap = { + [key: string]: string; +}; + +export type FileSubmissionRow = { + submission_id: string; + submitter_id: string; + entity_name: string; + file_name: string; + status: string; + outcome: string; + received_timestamp: string; + updated_at: string; + payor_code: string; + view_modal_content: FileSubmissionLogsModalContent[]; +}; + +export type FileSubmissionResult = { + header: string[]; + selected_status: string; + selected_sort: string; + query_str: string; + pagination_url_namespaces: string; + page: FileSubmissionRow[]; + page_num: number; + total_pages: number; +}; + +export type FileSubmissionLogsModalContent = { + log_id: string; + submission_id: string; + entity_name: string; + file_type: string; + validation_suite: string; + outcome: string; + has_html_log: number; + has_json_log: number; +}; + +export { useListSubmissions, useSubmissionFilters } from './useSubmissions'; diff --git a/apcd_cms/src/client/src/hooks/submissions/useSubmissions.ts b/apcd_cms/src/client/src/hooks/submissions/useSubmissions.ts new file mode 100644 index 00000000..fcf259b3 --- /dev/null +++ b/apcd_cms/src/client/src/hooks/submissions/useSubmissions.ts @@ -0,0 +1,56 @@ +import { useQuery, UseQueryResult } from 'react-query'; +import { fetchUtil } from 'utils/fetchUtil'; +import { FileSubmissionResult } from '.'; +import { FilterOptions } from 'hooks/admin'; //May want to refactor where this hook lives + +const getSubmissionFilters = async () => { + const url = 'submissions/list-submissions/api/options'; + const response = await fetchUtil({ url }); + return response; +}; + +export const useSubmissionFilters = (): UseQueryResult => { + const query = useQuery(['submissionFilters'], () => getSubmissionFilters(), { + staleTime: 5 * 60 * 1000, + cacheTime: 10 * 60 * 1000, + refetchOnWindowFocus: false, + }) as UseQueryResult; + + return { ...query }; +}; + +const getListSubmissions = async (params: any) => { + const url = `submissions/list-submissions/api/`; + const response = await fetchUtil({ + url, + params, + }); + return response.response; +}; + +export const useListSubmissions = ( + status?: string, + sort?: string, + submitterId?: string, + payorCode?: string, + page?: number +): UseQueryResult => { + const params: { + status?: string; + sort?: string; + submitterId?: string; + payorCode?: string; + page?: number; + } = { + status, + sort, + submitterId, + payorCode, + page, + }; + const query = useQuery(['list_submissions', params], () => + getListSubmissions(params) + ) as UseQueryResult; + + return { ...query }; +}; diff --git a/apcd_cms/src/client/src/main.tsx b/apcd_cms/src/client/src/main.tsx new file mode 100644 index 00000000..ace8018f --- /dev/null +++ b/apcd_cms/src/client/src/main.tsx @@ -0,0 +1,63 @@ +// library.tsx +import React from 'react'; +import ReactDOM from 'react-dom'; +import { BrowserRouter } from 'react-router-dom'; +import { AdminRegistrations } from './components/Admin/Registrations'; +import { ViewUsers } from './components/Admin/ViewUsers'; +import { AdminSubmissions } from './components/Admin/Submissions'; +import { AdminExtensions } from './components/Admin/Extensions'; +import { AdminExceptions } from './components/Admin/Exceptions'; +import { ViewExceptionModal } from './components/Admin/ViewExceptionModal'; +import { EditExceptionModal } from './components/Admin/EditExceptionModal'; +import { SubmitterRegistrationList } from './components/Submitter/Registrations'; +import { RegistrationForm } from 'apcd-components/Forms/Registrations'; +import { QueryClient, QueryClientProvider } from 'react-query'; +import { ExceptionFormPage } from './components/Submitter/Exceptions'; +import { ExtensionRequestForm } from 'apcd-components/Submitter/Extensions'; +import { ViewFileSubmissions } from './components/Submissions/ViewFileSubmissions'; +import { ViewSubmitterUsers } from 'apcd-components/Submitter/ViewSubmitterUsers'; + +const queryClient = new QueryClient(); + +function setupComponent(rootId: string, Component: React.ComponentType): void { + const root = document.getElementById(rootId); + if (root) { + ReactDOM.render( + + + + + , + root + ); + } +} + +// Mapping of element IDs to components +const componentMap: { [key: string]: React.ComponentType } = { + 'list-registrations-root': AdminRegistrations, + 'view-users-root': ViewUsers, + 'list-admin-submissions': AdminSubmissions, + 'admin-extensions-root': AdminExtensions, + 'admin-exceptions-root': AdminExceptions, + 'view-exception-modal-root': ViewExceptionModal, + 'edit-exception-modal-root': EditExceptionModal, + 'list-submitter-registrations-root': SubmitterRegistrationList, + 'registration-form-root': RegistrationForm, + 'exception-submission-root': ExceptionFormPage, + 'extension-submission-root': ExtensionRequestForm, + 'list-submissions-root': ViewFileSubmissions, + 'view-submitter-users-root': ViewSubmitterUsers, + // Add new components with html id in the list above. +}; + +function setupApp(): void { + Object.keys(componentMap).forEach((id) => { + const elem = document.getElementById(id); + if (elem) { + setupComponent(id, componentMap[id]); + } + }); +} + +document.addEventListener('DOMContentLoaded', setupApp); diff --git a/apcd_cms/src/client/src/react-app-env.d.ts b/apcd_cms/src/client/src/react-app-env.d.ts new file mode 100644 index 00000000..6431bc5f --- /dev/null +++ b/apcd_cms/src/client/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apcd_cms/src/client/src/setupTests.ts b/apcd_cms/src/client/src/setupTests.ts new file mode 100644 index 00000000..8f2609b7 --- /dev/null +++ b/apcd_cms/src/client/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/apcd_cms/src/client/src/utils/dateUtil.ts b/apcd_cms/src/client/src/utils/dateUtil.ts new file mode 100644 index 00000000..dd8a762c --- /dev/null +++ b/apcd_cms/src/client/src/utils/dateUtil.ts @@ -0,0 +1,101 @@ +export const formatDate = (dateString: string | number | Date): string => { + const date = new Date(dateString); + if (isNaN(date.getTime())) { + return ''; + } + + return new Intl.DateTimeFormat('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + hour12: true, + }).format(date); +}; + +export const formatModalDate = (dateString: string | number | Date): string => { + return formatDate(dateString) + .replace('.', '') + .replace('AM', 'a.m.') + .replace('PM', 'p.m.'); +}; + +/** + * + * @param period string - Jan. 2024 as example + * @returns string. 2024-01 for Jan. 2024. + */ +export const convertPeriodLabelToApiValue = (period: string): string | null => { + // Return as-is if already in expected format + if (/^\d{4}-(0[1-9]|1[0-2])$/.test(period)) { + return period; + } + const monthMap: Record = { + Jan: '01', + Feb: '02', + Mar: '03', + Apr: '04', + May: '05', + Jun: '06', + Jul: '07', + Aug: '08', + Sep: '09', + Oct: '10', + Nov: '11', + Dec: '12', + }; + + const match = period.match(/^([A-Za-z]{3})\.?\s(\d{4})$/); + if (!match) { + console.log(`Invalid period format: ${period}`); + return period; + } + + const [_, month, year] = match; + const numericMonth = monthMap[month]; + + if (!numericMonth) { + console.log(`Invalid month: ${month} in ${period}`); + return period; + } + + return `${year}-${numericMonth}`; +}; + +export const convertApiValueToPeriodLabel = (period: string): string | null => { + if (/^([A-Za-z]{3})\.?\s(\d{4})$/.test(period)) { + return period; + } + + const monthMap: Record = { + '01': 'Jan', + '02': 'Feb', + '03': 'Mar', + '04': 'Apr', + '05': 'May', + '06': 'Jun', + '07': 'Jul', + '08': 'Aug', + '09': 'Sep', + '10': 'Oct', + '11': 'Nov', + '12': 'Dec', + }; + + const match = period.match(/^(\d{4})-(0[1-9]|1[0-2])$/); + if (!match) { + console.log(`Invalid period format: ${period}`); + return period; + } + + const [_, year, month] = match; + const stringMonth = monthMap[month]; + + if (!stringMonth) { + console.log(`Invalid month: ${month} in ${period}`); + return period; + } + + return `${stringMonth} ${year}`; +}; diff --git a/apcd_cms/src/client/src/utils/fetchUtil.ts b/apcd_cms/src/client/src/utils/fetchUtil.ts new file mode 100644 index 00000000..7aa60445 --- /dev/null +++ b/apcd_cms/src/client/src/utils/fetchUtil.ts @@ -0,0 +1,54 @@ +import Cookies from 'js-cookie'; + +export class FetchError extends Error { + public status: number; + + constructor(json: any, response: Response) { + super(json.message); + this.name = 'FetchError'; + this.status = response.status; + } +} + +interface FetchUtilParams { + url: string; + method?: string; + params?: Record; + headers?: Record; + body?: any; +} + +export async function fetchUtil({ + url, + params, + method = 'GET', + headers = {}, + body, + ...options +}: FetchUtilParams) { + const request = new URL(url, window.location.origin); + for (const [key, val] of Object.entries(params || {})) { + request.searchParams.append(key, val); + } + + const fetchParams: RequestInit = { + method, + credentials: 'same-origin', + headers: { + 'X-CSRFToken': Cookies.get('csrftoken') || '', + 'Content-Type': 'application/json', + ...headers, + }, + body: body ? JSON.stringify(body) : undefined, + ...options, + }; + + const response = await fetch(request.toString(), fetchParams); + const json = await response.json(); + + if (!response.ok) { + throw new FetchError(json, response); + } + + return json; +} diff --git a/apcd_cms/src/client/src/utils/index.ts b/apcd_cms/src/client/src/utils/index.ts new file mode 100644 index 00000000..30491281 --- /dev/null +++ b/apcd_cms/src/client/src/utils/index.ts @@ -0,0 +1,4 @@ +// index.ts +export * from './dateUtil'; +export * from './fetchUtil'; +export * from './stringUtil'; diff --git a/apcd_cms/src/client/src/utils/stringUtil.ts b/apcd_cms/src/client/src/utils/stringUtil.ts new file mode 100644 index 00000000..29097684 --- /dev/null +++ b/apcd_cms/src/client/src/utils/stringUtil.ts @@ -0,0 +1,7 @@ +export const titleCase = (field: string): string => { + if (!field) return field; + return field + .split(' ') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); +}; diff --git a/apcd_cms/src/client/src/vite-env.d.ts b/apcd_cms/src/client/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/apcd_cms/src/client/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apcd_cms/src/client/stats.html b/apcd_cms/src/client/stats.html new file mode 100644 index 00000000..d1c4443f --- /dev/null +++ b/apcd_cms/src/client/stats.html @@ -0,0 +1,4842 @@ + + + + + + + + Rollup Visualizer + + + +
+ + + + + diff --git a/apcd_cms/src/client/tsconfig.json b/apcd_cms/src/client/tsconfig.json new file mode 100644 index 00000000..6287c20b --- /dev/null +++ b/apcd_cms/src/client/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "apcd-components/*":["src/components/*"], + "core-components/*": ["src/core-components/*"], + "core-wrappers/*": ["src/core-wrappers/*"], + "hooks/*": ["src/hooks/*"], + "utils/*": ["src/utils/*"], + }, + "target": "ESNext", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "ESNext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "exclude": [ + "src/**/*.spec.ts", + "src/**/*.test.ts", + "src/**/*.spec.tsx", + "src/**/*.test.tsx", + "src/**/*.spec.js", + "src/**/*.test.js", + "src/**/*.spec.jsx", + "src/**/*.test.jsx" + ], + "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx", "main.tsx"] +} diff --git a/apcd_cms/src/client/vite.config.ts b/apcd_cms/src/client/vite.config.ts new file mode 100644 index 00000000..af414d26 --- /dev/null +++ b/apcd_cms/src/client/vite.config.ts @@ -0,0 +1,45 @@ +import eslint from '@rollup/plugin-eslint'; +import { defineConfig, type PluginOption } from 'vite'; +import react from '@vitejs/plugin-react'; +import path, {resolve} from 'path'; + + +export default defineConfig({ + css: { preprocessorOptions: { scss: { charset: false } } }, + build: { + outDir: 'dist', + rollupOptions: { + input: { + imports: path.resolve(__dirname, 'react-assets.html'), + }, + output: { + entryFileNames: 'static/assets/[name].[hash].js', + chunkFileNames: 'static/assets/[name].[hash].js', + assetFileNames: 'static/assets/[name].[hash].[ext]' + } + }, + }, + resolve: { + alias: { + 'apcd-components': resolve(__dirname, 'src/components'), + 'core-wrappers': resolve(__dirname, 'src/core-wrappers'), + 'core-components': resolve(__dirname, 'src/core-components'), + 'hooks': resolve(__dirname, 'src/hooks'), + 'utils': resolve(__dirname, 'src/utils'), + } + }, + server: { + port: 3000, + host: 'localhost', + hmr: { + port: 3000, + }, + }, + plugins: [ + {...eslint({include: 'src/**/*.+(js|jsx|ts|tsx)', fix: false}), enforce: 'pre', }, + react(), + ], + optimizeDeps: { + include: ['react-refresh'], + }, +}) \ No newline at end of file diff --git a/apcd_cms/src/taccsite_cms/custom_app_settings.py b/apcd_cms/src/taccsite_cms/custom_app_settings.py index 3784c036..aef025e0 100644 --- a/apcd_cms/src/taccsite_cms/custom_app_settings.py +++ b/apcd_cms/src/taccsite_cms/custom_app_settings.py @@ -1,4 +1,4 @@ -CUSTOM_APPS = ['apps.admin_regis_table', 'apps.apcd_login', 'apps.registrations', 'apps.submissions', 'apps.exception', 'apps.admin_submissions', 'apps.admin_extension', 'apps.admin_exception', 'apps.extension', 'apps.submitter_renewals_listing', 'apps.view_users', 'apps.components.paginator', 'apps.utils'] +CUSTOM_APPS = ['apps.admin_regis_table', 'apps.apcd_login', 'apps.registrations', 'apps.submissions', 'apps.exception', 'apps.admin_submissions', 'apps.admin_extension', 'apps.admin_exception', 'apps.extension', 'apps.submitter_renewals_listing', 'apps.view_users', 'apps.components.paginator', 'apps.utils', 'apps.common_api', 'apps.view_submitter_users'] CUSTOM_MIDDLEWARE = [] -STATICFILES_DIRS = ('taccsite_custom/apcd_cms', 'apps/admin_regis_table', 'apps/submissions', 'apps/exception', 'apps/extension', 'apps/submitter_renewals_listing', 'apps/view_users', 'apps/components/paginator', 'apps/utils') +STATICFILES_DIRS = ('taccsite_custom/apcd_cms', 'apps/admin_regis_table', 'apps/registrations', 'apps/submissions', 'apps/exception', 'apps/extension', 'apps/submitter_renewals_listing', 'apps/view_users', 'apps/components/paginator', 'apps/utils', 'client/dist', 'apps/common_api') diff --git a/apcd_cms/src/taccsite_cms/templates/guides/getting_started.tam.html b/apcd_cms/src/taccsite_cms/templates/guides/getting_started.tam.html new file mode 100644 index 00000000..f30b0f94 --- /dev/null +++ b/apcd_cms/src/taccsite_cms/templates/guides/getting_started.tam.html @@ -0,0 +1,21 @@ +{% extends "guide.html" %} +{% load cms_tags static tacc_uri_shortcuts %} + +{% block guide %} + {% site_uri as site_uri %} +
+
+

NEW Getting Started

+ +

NEW Account Holders

+ +

NEW If you already have an account, you may log in by clicking the Log in link at the top right of the page.

+ +

NEW Creating an Account

+ +

NEW Before you can access the Portal, you must first have an active account with TACC.

+ +

NEW If you are a new TACC user, you may sign up for a new TACC account.

+
+
+{% endblock guide %} \ No newline at end of file diff --git a/apcd_cms/src/taccsite_cms/urls_custom.py b/apcd_cms/src/taccsite_cms/urls_custom.py index cfc03d8d..037e9259 100644 --- a/apcd_cms/src/taccsite_cms/urls_custom.py +++ b/apcd_cms/src/taccsite_cms/urls_custom.py @@ -6,10 +6,12 @@ path('administration/', include('apps.admin_submissions.urls', namespace='admin_submission')), path('administration/', include('apps.admin_exception.urls', namespace='admin_exception')), path('administration/', include('apps.admin_extension.urls', namespace='admin_extension')), + path('administration/', include('apps.view_submitter_users.urls', namespace='view_submitter_users')), path('apcd-login/', include('apps.apcd_login.urls', namespace='apcd_login')), path('register/', include('apps.registrations.urls', namespace='register')), path('register/', include('apps.submitter_renewals_listing.urls', namespace='submitter_regis_table')), path('submissions/', include('apps.extension.urls', namespace='extension')), path('submissions/', include('apps.exception.urls', namespace='exception')), - path('submissions/', include('apps.submissions.urls', namespace='submissions')) + path('submissions/', include('apps.submissions.urls', namespace='submissions')), + path('common_api/', include('apps.common_api.urls', namespace='common_api')) ] diff --git a/apcd_cms/src/taccsite_custom/apcd_cms/static/apcd-components.es.js b/apcd_cms/src/taccsite_custom/apcd_cms/static/apcd-components.es.js new file mode 100755 index 00000000..e69de29b diff --git a/apcd_cms/src/taccsite_custom/apcd_cms/static/apcd_cms/css/table.css b/apcd_cms/src/taccsite_custom/apcd_cms/static/apcd_cms/css/table.css index 47d34670..8ef0cf3f 100644 --- a/apcd_cms/src/taccsite_custom/apcd_cms/static/apcd_cms/css/table.css +++ b/apcd_cms/src/taccsite_custom/apcd_cms/static/apcd_cms/css/table.css @@ -107,9 +107,13 @@ table { .filter-container { margin-bottom: 30px; width: auto; + } .filter-content { float: right; + display: flex; + align-items: center; + gap: 10px; } /* To reveal floated child (.filter-content) on narrow screen i.e. "clearfix" */ /* SEE: https://www.google.com/search?q=clearfix */ @@ -120,13 +124,5 @@ table { } .status-filter { - color: var(--global-color-link-on-light--normal); - width: 150px; - appearance: none; - -webkit-appearance: none; - - background-image: url("data:image/svg+xml,%3Csvg id='tacc-arrows' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 130.34 292.4'%3E%3Cdefs%3E%3Cstyle%3E.arrow%7Bfill:%23484848;%7D%3C/style%3E%3C/defs%3E%3Cg id='tacc-arrows——root'%3E%3Cpath id='Path_3088' data-name='Path 3088' class='arrow' d='M82.24,96.17,148.09,0l64.45,96.17Z' transform='translate(-82.2)'/%3E%3Cpath id='Path_3089' data-name='Path 3089' class='arrow' d='M212.5,196.23,146.65,292.4,82.2,196.23Z' transform='translate(-82.2)'/%3E%3C/g%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: right 6px top 50%; /* 5px design * 1.2 design-to-app ratio */ - background-size: auto 10px; /* ~8px design * 1.2 design-to-app ratio (rounded) */ + width: max-content; } diff --git a/apcd_cms/src/taccsite_custom/apcd_cms/templates/assets_custom.html b/apcd_cms/src/taccsite_custom/apcd_cms/templates/assets_custom.html index 2a3cccb8..8a68833c 100644 --- a/apcd_cms/src/taccsite_custom/apcd_cms/templates/assets_custom.html +++ b/apcd_cms/src/taccsite_custom/apcd_cms/templates/assets_custom.html @@ -11,7 +11,7 @@ {% with settings.PORTAL_FAVICON as favicon %} - + {% endwith %} diff --git a/apcd_cms/src/taccsite_custom/apcd_cms/templates/snippets/tup-175-css-alerts-messages-ui-pattern.html b/apcd_cms/src/taccsite_custom/apcd_cms/templates/snippets/tup-175-css-alerts-messages-ui-pattern.html index d3ebdba5..e6b17351 100644 --- a/apcd_cms/src/taccsite_custom/apcd_cms/templates/snippets/tup-175-css-alerts-messages-ui-pattern.html +++ b/apcd_cms/src/taccsite_custom/apcd_cms/templates/snippets/tup-175-css-alerts-messages-ui-pattern.html @@ -1,5 +1,5 @@ {# Load message styles from Core-Styles at the same version Core-CMS has #} -{# FAQ: APCD-CMS uses default TACC_CORE_STYLES_VERSION = 0, so v0.13.0 #} +{# FAQ: apcd_cms uses default TACC_CORE_STYLES_VERSION = 0, so v0.13.0 #} {# HACK: Load up-to-date Core-Styles colors #} {# FAQ: Core-Styles v0.13.0 has outdated colors, loading directly overrides Core-CMS site.css color fix #} diff --git a/apcd_cms/src/taccsite_custom/apcd_cms/templates/standard.html b/apcd_cms/src/taccsite_custom/apcd_cms/templates/standard.html new file mode 100644 index 00000000..36fee9e2 --- /dev/null +++ b/apcd_cms/src/taccsite_custom/apcd_cms/templates/standard.html @@ -0,0 +1,23 @@ + +{% extends "standard.html" %} +{% load cms_tags %} + +{% block assets_custom %} + {{ block.super }} + + {% include "./assets_custom.html" %} + + {% if settings.DEBUG %} + + + + {% else %} + {% include "./react-asset.html" %} + {% endif %} +{% endblock assets_custom %}