From d3ed1f40606ec46d8ad78bd7fd144b1d814b5740 Mon Sep 17 00:00:00 2001 From: Chandra Y Date: Fri, 17 Jan 2025 14:57:18 -0600 Subject: [PATCH] Merging feat/apcd react conversion into main (#411) * Initial commit - using react with APCD admin registration list page (#276) * Initial commit - using react with APCD page * remove visualizer * Remove print statements * Renamed shared-components to core-components * Initial commit - using react with APCD admin registration list page (#276) * Initial commit - using react with APCD page * remove visualizer * Remove print statements * Renamed shared-components to core-components * Update README.md for APCD * Fix dockerfile for static * Initial commit - using react with APCD admin registration list page (#276) * Initial commit - using react with APCD page * remove visualizer * Remove print statements * Renamed shared-components to core-components * Update README.md for APCD * Fix dockerfile for static * Install nodejs as part of docker image * Docker compose dev adjustments for react * task/WP-443 Convert Admin Submissions to React (#288) * apcd admin submissions react page version 1 * moved filter and sort functionality to react * Added View logs modal using reactstrap modal --------- Co-authored-by: Chandra Y * Task/wp 425 admin user listing (#286) * feat: Add ViewUsers component * chore: Update Docker Compose dev configuration for React * refactor: Update ViewUsers component and related files * refactor: Update ViewUsers component and related files * feat: Add user action dropdown in ViewUsers component * Filter by Status and Org now work * URL updated w/ status and org * URL updates to show status and/or organization --------- Co-authored-by: Chandra Y * Fix merge issue * [ACPD React Conversion]: Setup vite local and add base template with react (#294) * Setup vite local and template with react content * Update Makefile * Update README.md to reflect new changes * Initial version (#299) Modal windows not included * Task/WP-429 list registrations: filters, pagination and view modal (#298) * List registrations: filters, pagination and view modal * Add pending edit modal and fix org status * List Admin Extensions React Conversion (#289) * first run at the react conversion * Update list_admin_extension.html from merge feat branch * Updated incorrect import --------- Co-authored-by: Chandra Y * Add formik, reactstrap, yup for APCD React forms (#302) * temp commit * Task/wp 425 view edit modals (#297) * feat: Add user action dropdown in ViewUsers component * Add ViewRecordModal component and styles for user details modal * Update ViewRecordModal component and styles for user details modal * Update ViewRecordModal component and styles for user details modal * Create Edit Record modal * Add Success and Error modals * Update EditRecordModal component and fix error handling * Add support for fetchUtil request method and use it in EditRecordModal * Add update user method * Add pagination to ViewUsersTable component * Update ViewUsersTable component with duplicate path in urls.py * Update EditRecordModal component and fix error handling * Remove link --------- Co-authored-by: Chandra Y * Submitter Registration List using React (#307) * Bug/wp 690 empty values should be None (#310) * Update RegistrationList and ViewRegistrationModal to display 'None' when year, reg_status, fein, license, or naic is undefined or null --------- Co-authored-by: Chandra Y * WP-713 - add pagination to admin submissions (#322) * task/WP-712-Create-useEntity-Hook (#324) Co-authored-by: Chandra Y * Task/WP-437-Exception-Form-React (#326) * - Moves templates out of exception_submission_form dir * task/wp-437-exception-form-react Initial commit - adds CDL hook and cdl class to common_api apps - Creates exception form id to reference React component - Updates template to only reference exception form id - Adds ExceptionForm React component TODO: - Button actions - submitting form - adding non dynamic fields - option for non threshold exception submissions * Additional additions for initial commit * Update apcd-cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.tsx Co-authored-by: Chandra Y * Update apcd-cms/src/client/src/hooks/cdls/useCDLs.ts Co-authored-by: Chandra Y * Update apcd-cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.tsx Co-authored-by: Chandra Y * Linting --------- Co-authored-by: Chandra Y * WP-711: Do not use hardcoded org list (#331) * Wp 579 request extensions form (#332) * feat: Add ExtensionRequestForm component and related files * chore: Update ExtensionsForm component buttons styling * feat: Improve accessibility and usability of ExtensionsForm component * Task/wp 715 react exception form follow on (#330) * 10/15 Loads other/threshold dynamically. Add/remove threshold working. Dynamically appending unique index for thresholdform fields * - Adds validation schema and initial values using exception object passed from ExceptionForm - Adds styling changes * - Formatting child form fields to pass and iterate over in parent component * - Adds post changes in view * - Uses formik field to store values in child component * - Child component fields update * - Debugging Form rendering * - Updated to ExceptionFormPage * - POST request alteration - DB insert altered to match views - Removed FormFeedback from ExcpetionMessage as Formik's Field is no longer linked to Reactstrap's Input component - Created style for invalid inputs * - Unstaged changes left behind from last commit * Clear fields when exception type is changed Co-authored-by: Chandra Y * Moves header for exception type selection near field Co-authored-by: Chandra Y * Updates title of page to reflect type of exception Co-authored-by: Chandra Y * - Updates button text if an exception has been submitted * Prettier * - Removes debug statement --------- Co-authored-by: Chandra Y * Split into two components (#333) * Task/jira wp431 user submissions listing Convert to REACT (#336) * added submissions folder in hooks and updating submissions to react * for examination by C * Fixing up errors * for examination by C-2 * for examination by C-3 * added last c edit * Update apcd-cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.tsx --------- Co-authored-by: Chandra Y * Use dynamic data in business name field in extensions. Use relative links (#337) * [APCD][React] User friendly date time display in UI (#338) * Handle datetime usage in APCD * Fix date time in Extension Listing * Task/wp 735 other exception form (#341) * task/WP-735-Other-Exception-Form * Removes unused templates and styles sheets on the app side * - Adds missing asterisk from expiration date * WP-720: [APCD][React] Extension form submit hookup (#340) * Submit handling for extension * Add error message ui element * - Suggested styles changes for extension form (#342) * Update apcd-cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx Co-authored-by: sophia-massie <96220951+sophia-massie@users.noreply.github.com> * Delete unused templates and css --------- Co-authored-by: sophia-massie <96220951+sophia-massie@users.noreply.github.com> * APCD react feature - use react-asset.html instead of react-assets.html * Exception list React implementation (#329) * Initial version Modal windows not included * View modal and paginator implementation. * Cleaning code * Edit Exception modal, initial version. * Edit Extensions modal. * Modal windows review changes. --------- Co-authored-by: Chandra Y * task/WP-580 - Registration form react conversion (#339) * Merge with feature branch and initial commit * Registration form - React components * Registration form - add registration form to client index to pick up react form * Registration form - clear out django template + add div for react form to be served to * Registration form - styling updates to better mesh with react form * Clean up warnings + add required text + some style adjustments * Factor out use of reactstrap's formtext to better align with existing form's styling + limit contacts and entities to 5 entries each (+ add message about submitting ticket for add. entities) * Some client hooks cleanup * Add submission method for registration form * Adjust registration form post + writing to db for registration funtions to work with react form + submission method * Fix submission - add styling for errors to show on each field, provide initial values for on_behalf_of and type, adjust how errors are passed from the view back to react on submission * Update apcd-cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx single braces instead of double braces * Return loading spinner on loading Co-authored-by: sophia-massie <96220951+sophia-massie@users.noreply.github.com> * Update number validation messages + rename reg form data hook --------- Co-authored-by: Chandra Y Co-authored-by: sophia-massie <96220951+sophia-massie@users.noreply.github.com> * Run prettier * Admin Extensions React Conversion: Filters, Pagination, Modals (#335) Branch that implements filtering and pagination on listing page as well as view and edit modals. First pass with many improvements needed in a later PR. --------- Co-authored-by: Chandra Y * prettier run * WP-738 Hook up Edit Registration and Renew Registration to Registration Form. (#344) * Hook up edit registration and renew registration * Fix bug in RegistrationList * zip code has spaces, strip them. * Handle deletion * Bug/WP-749: ViewUsers - fix filter usage. (#346) * ViewUsers - fix filters * Adjust css for sizing of org filter * Task/wp 743 exception form testing changes (#345) * - Clears field codes when file type is not selected * - Adds required badges to match CEP forms - Resets field codes on file type change - Changes text to alert users that changing exception type will erase changes - Improves form validation messages * - Removes unused static css from template - Adds missing class to a badge * - Adds error message next to submit if fields are invalid on submit * - Adds missing class from a field --------- Co-authored-by: Chandra Y * Registration Table - fix clear selection button (#347) * ExtensionForm fixes (#351) * View Users various fixes * chore: delete seemingly erroneous entity (#349) Co-authored-by: Chandra Y * View Users: clear options button behavior (#352) * Task/WP-746-styles-primary-color-blue (#348) * bugs/WP-756: [APCD][React] Fix modal close button (#355) * Adjust modal close icon * Adjust modals to use ModalHeader with close button * Task/wp 441 exception list - Testing session fixes (#356) * Initial version Modal windows not included * View modal and paginator implementation. * Cleaning code * Edit Exception modal, initial version. * Edit Extensions modal. * Modal windows review changes. * Testing feedback fixes. * Cleaning up code * Cleaning up code * Delete duplicated code. * Removing unnecessary styling classes * Fixing merging conflicts --------- Co-authored-by: Chandra Y * bug/WP-741: Registration Form cleanup tasks (#358) * Move 'On behalf of' help text div to arrange correctly under radio buttons * Fix validation messages for entity grouped 'atleast one' inputs + checkboxes not writing correctly to db * Fix checkboxes writing to db from reg form - inputs now return bool instead of str * Task/wp 751 submission listing bugs (#357) * - Updated view and url to get filters and filtered submission content - Moved styles from app to client - Added sort options to filter hooks - Created client side title case util so it won't break pages on response if response does not exist * - Staged the wrong changes. WIP from Nov 12 * - Adds filter styles to filter-contents class rather that hard coding * - Added some debug statements to find where the modal data goes missing * - Final configuring of both submitter submission page and admin submission page * - Catches undefined for string utils - Removes repeated header * - Linting --------- Co-authored-by: Chandra Y * Fix merge issue and prettier * Handle empty data scenario (#354) * WP-763: [APCD] Use field wrapper for registration, exception and extension forms. (#360) * core-wrapper and usage of field-wrapper * ExceptionForm fieldwrapper * Registration Changes * bug/WP-741: Missed bugs follow on (#359) * Import get_registration db util functions to view * Front-end fixes: Add/Remove Entity/Contacts button wrapping, Entity/Contact header styling, add initial value + initial touched for state field * Add style class for bolding nested headers on form * Add some padding above labels for entity and contact entries * Data transfer bugs when pre-loading data to form: for self value now goes to form as string rather than bool, and type display value is mapped to the database value --------- Co-authored-by: Chandra Y * applicable data period fix (#361) * task/WP-742: Fix renew registration in react (#362) * Strip trailing slash from reg_id coming from submitter reg listing to get to renew form * Renew form hookup fixes: change type for useRegFormData function to capture all data passed from view + index reg year up by 1 on form population to match prod behavior * Update apcd-cms/src/apps/registrations/views.py Co-authored-by: Chandra Y --------- Co-authored-by: Chandra Y * bug/WP-769-Submission-Sort-Bug (#363) * bug/WP-709-Submission-Sort-Bug - Adds a sort of filtered list after intial API date sort * - Removes redundant sort * - Fixes the clear options button on submitter submissions table * Feat/extensions listing residual issues (#364) * new branch off latest feat branch updates. removed a few residual debug messages and fixed styling * bugs/WP-756: [APCD][React] Fix modal close button (#355) * Adjust modal close icon * Adjust modals to use ModalHeader with close button * Task/wp 441 exception list - Testing session fixes (#356) * Initial version Modal windows not included * View modal and paginator implementation. * Cleaning code * Edit Exception modal, initial version. * Edit Extensions modal. * Modal windows review changes. * Testing feedback fixes. * Cleaning up code * Cleaning up code * Delete duplicated code. * Removing unnecessary styling classes * Fixing merging conflicts --------- Co-authored-by: Chandra Y * bug/WP-741: Registration Form cleanup tasks (#358) * Move 'On behalf of' help text div to arrange correctly under radio buttons * Fix validation messages for entity grouped 'atleast one' inputs + checkboxes not writing correctly to db * Fix checkboxes writing to db from reg form - inputs now return bool instead of str * Task/wp 751 submission listing bugs (#357) * - Updated view and url to get filters and filtered submission content - Moved styles from app to client - Added sort options to filter hooks - Created client side title case util so it won't break pages on response if response does not exist * - Staged the wrong changes. WIP from Nov 12 * - Adds filter styles to filter-contents class rather that hard coding * - Added some debug statements to find where the modal data goes missing * - Final configuring of both submitter submission page and admin submission page * - Catches undefined for string utils - Removes repeated header * - Linting --------- Co-authored-by: Chandra Y * Fix merge issue and prettier --------- Co-authored-by: Chandra Y Co-authored-by: Juan Co-authored-by: Garrett Edmonds <43251554+edmondsgarrett@users.noreply.github.com> Co-authored-by: sophia-massie <96220951+sophia-massie@users.noreply.github.com> * made Pending default and fixed clear options button so its consistent with other pages (#365) * Task/wp 759 exeption listing bugs (#366) * Exception Listing bugs fixed * FieldWrapper applied * Modal header and close button fix --------- Co-authored-by: Chandra Y * prettier fix * task/WP-700: Add status to view record modal + default filter registration records to 'Received' status (#369) * Add registration status to View Record modal * Show only status='Received' records on admin registrations listing on load (by default) * Title case for registration status within view modal * WP-201: add entity organization to user file submissions (#368) * WP-201: add entity organization to user file submissions * Unifying submission modal and css. * bug/extension-expected-date (#367) * - Prevents user from changing Current Expected date from database when filling out extension form * - Fixes key console error for mapped options - Removes deleted css sheet from extension form templates - Removes required badge from Current Expected Date field * Data Refresh and Display Issues (#370) * fixed a few issues with refresh etc * Fixed multiple issues including data not being refetched and displayed properly and small styling issues * more small polishing * task/stashed-extension-modal-styles (#371) Style ideas - not needed just left over work when trying to figure out the useEffect yesterday for extension modal Co-authored-by: Carrie Arnold --------- Co-authored-by: sophia-massie <96220951+sophia-massie@users.noreply.github.com> Co-authored-by: Chandra Y * WP-754: submissions - html and json log download (#374) * WP-754: submissions - html and json log download * fix bug in admin user * Add 'No Data found' message for all listing tables if data from response is empty (#375) Co-authored-by: Chandra Y * distinguish page differences (#372) Co-authored-by: Chandra Y * Rename apcd-cms to acpd_cms, prepare for merge from main * manual merge to new folder structure (#378) Co-authored-by: Chandra Y * fix apcd image path * add urls.py for check-submitter-role * WP-777 - json download issue (#380) * Manual merge for apcd - folder rename (#376) Co-authored-by: Chandra Y * Bug/WP-792: disable submit if form is not modified. (#384) * WP-793: Check for null logs (#383) * Bugs/WP-789: Extension Edit Modal (#382) * WP-789:Extension Edit Modal fixes * New api is only for admin users * Remove print * handle "None" for expiration date * Remove duplicate main.tsx * Bugs/WP-795: clear selection button uniformity (#388) * WP-795: clear options button similarity across all pages * set styles * WP-796 - registration list needs to update on modal edits (#391) * WP-799 fix ticket creation api and handle error message (#387) * tasl/WP-802 & WP-808: Remaining admin default filters (#394) * Default filter admin submissions listing to 'status=In Process' * Default filter admin users listing to 'status=Active' * Merge features from main to apcd feature branch (#393) * Merge features from main to apcd feature branch * Fix id field --------- Co-authored-by: Garrett Edmonds <43251554+edmondsgarrett@users.noreply.github.com> * Fix Vite build warning * bug/Exception-Modal-Success-Exit-Icon-Missing (#397) - Removes toggle from success and error message to mimic behavior in other edit modals - Will revisit handling of success messages after React initial release * Task/WP-762--Use-Core-Component-Buttons (#381) * react-strap buttons * submit attribute for formik * edit record modal submit attribute --------- Co-authored-by: Chandra Y * fix merge issue * Task/WP-764: Implement field wrapper for edit modals (#385) * initial commit * Validation Users Edit Record Modal * Exception Modal * ExtensionModal * error above, succsess inline * EditRecord QueryWrapper * QueryWrapper ExceptionModal * pill inline fix * removed non required pills --------- Co-authored-by: Chandra Y * Quick Fix: APCD, List registrations for submitter is broken (#398) * Fix syntax error in sql * move left join before where * File Submissions title update (#399) * Update admin list users title + description (#400) * Task/WP-157: View Submitter Users (New Admin Page) (#386) * Created new blank page at URL administration/view-submitter-users * Began building of Submitter Users Page * All Users shown on table; working on filtering by Submitter-User role * Established SQL query to get submitter users; set up views.py * Still working on getting the site to load the data * Got table of submitter users to appear * View modal opens and closes * Edit Modal opens and closes; can't edit records yet * Edit modal updates user names and emails correctly * Added View Submitter Users site to navbar * Linted client code * Removed changes to apcd_cms/src/client/main.tsx * Removed extraneous HTML files and commented-out portions * Update apcd_cms/src/apps/utils/apcd_database.py Simplify the database connection Co-authored-by: Chandra Y * Update apcd_cms/src/apps/utils/apcd_database.py Sort users by user ID Co-authored-by: Chandra Y * Update apcd_cms/src/apps/utils/apcd_database.py Co-authored-by: Chandra Y --------- Co-authored-by: Jeff McMillen Co-authored-by: Chandra Y * Restrict valid dates for both exception types to format MM/DD/YYYY (#396) Co-authored-by: Chandra Y * bug/WP-820-exp-date-exception-edit-modal (#402) * bug/WP-820-exp-date-exception-edit-modal * - Adds new label for clarity * [APCD] Exception, Submission and navigation bugs (#401) * Bugs from testing session * revert testing change * WP-821[APCD] Writing the required threshold to DB (#403) * Task/WP-822: Improve Submitter Users Page (#405) * Reorganized Submitter Users table * Added filters for status and payor code * View Record shows all row data plus user email * Edit Record shows editable fields and required data * Payor codes now shown as organization names * Linted client-side code * Payor Code filter now shows organization names instead of codes * Removed extraneous console logs * Fix payor code filter to check against display value in view * Edit submitter user modal adjustments: display success/error messages instead of modals, bring submit button to same style as like modals in portal * Remove leftover logging --------- Co-authored-by: Jeff McMillen Co-authored-by: Garrett Edmonds * fix - merge issue - undo non apcd dirs * Merge branch 'main' into feat/apcd-react-conversion * undo a2cps_cms change * more merge issues * adding .env * cipp merge issues * EOF --------- Co-authored-by: Garrett Edmonds Co-authored-by: Shayan Khan Co-authored-by: Van Go <35277477+van-go@users.noreply.github.com> Co-authored-by: Juan Co-authored-by: Carrie Arnold Co-authored-by: sophia-massie <96220951+sophia-massie@users.noreply.github.com> Co-authored-by: davidmtacc Co-authored-by: Garrett Edmonds <43251554+edmondsgarrett@users.noreply.github.com> Co-authored-by: Wesley B <62723358+wesleyboar@users.noreply.github.com> Co-authored-by: Jacob Lowe <40873986+jalowe13@users.noreply.github.com> Co-authored-by: Jeff McMillen Co-authored-by: Jeff McMillen --- .github/workflows/apcd-cms.yml | 2 +- apcd_cms/Dockerfile | 12 +- apcd_cms/README.md | 53 + .../templates/list_admin_exception.html | 99 +- .../templates/view_admin_exception_modal.html | 58 +- apcd_cms/src/apps/admin_exception/urls.py | 10 +- apcd_cms/src/apps/admin_exception/views.py | 206 +- .../static/admin_extension/css/modal.css | 4 + .../templates/list_admin_extension.html | 122 +- apcd_cms/src/apps/admin_extension/urls.py | 12 +- apcd_cms/src/apps/admin_extension/views.py | 185 +- .../static/admin_regis_table/css/table.css | 1 + .../templates/create_submitter_error.html | 18 - .../templates/create_submitter_modal.html | 76 - .../templates/create_submitter_success.html | 13 - .../templates/edit_registration_error.html | 16 - .../templates/edit_registration_modal.html | 26 - .../templates/edit_registration_success.html | 13 - .../templates/list_registrations.html | 108 +- .../templates/view_registration_modal.html | 117 - apcd_cms/src/apps/admin_regis_table/urls.py | 8 +- apcd_cms/src/apps/admin_regis_table/views.py | 166 +- .../admin_submissions/css/admin_table.css | 21 - .../templates/list_admin_submissions.html | 99 +- apcd_cms/src/apps/admin_submissions/urls.py | 10 +- apcd_cms/src/apps/admin_submissions/views.py | 191 +- apcd_cms/src/apps/common_api/apps.py | 4 + apcd_cms/src/apps/common_api/urls.py | 10 + apcd_cms/src/apps/common_api/views.py | 107 + .../forms/css/exception_submission_form.css | 45 - .../exception_err_no_sub_id.html | 0 .../templates/exception_submission_form.html | 11 + .../exception_form_success.html | 13 - .../exception_other_form.html | 181 - .../exception_selection_page.html | 50 - .../exception_submission_error.html | 18 - .../exception_threshold_form.html | 481 - apcd_cms/src/apps/exception/urls.py | 11 +- apcd_cms/src/apps/exception/views.py | 208 +- .../forms/css/extension_submission_form.css | 47 - .../extension_err_no_sub_id.html | 30 - .../extension_form_success.html | 13 - .../extension_submission_error.html | 18 - .../extension_submission_form.html | 442 +- apcd_cms/src/apps/extension/urls.py | 6 +- apcd_cms/src/apps/extension/views.py | 122 +- .../registrations/css/submission_form.css | 19 +- .../templates/registration_form.html | 18 + .../registration_form_body.html | 26 +- .../registration_form_scripts.html | 6 +- .../submission_form/submission_form.html | 85 - apcd_cms/src/apps/registrations/urls.py | 6 +- apcd_cms/src/apps/registrations/views.py | 74 +- .../static/submissions/css/table.css | 12 +- .../templates/list_submissions.html | 93 +- apcd_cms/src/apps/submissions/urls.py | 11 +- apcd_cms/src/apps/submissions/views.py | 151 +- .../list_submitter_registrations.html | 113 +- .../templates/submitter_listing_error.html | 14 - .../apps/submitter_renewals_listing/urls.py | 7 +- .../apps/submitter_renewals_listing/views.py | 64 +- apcd_cms/src/apps/utils/apcd_database.py | 474 +- .../utils/registrations_data_formatting.py | 46 +- .../src/apps/view_submitter_users/__init__.py | 0 .../src/apps/view_submitter_users/apps.py | 4 + .../templates/view_submitter_users.html | 12 + .../src/apps/view_submitter_users/urls.py | 12 + .../src/apps/view_submitter_users/views.py | 195 + .../static/view_users_table/css/table.css | 19 +- .../apps/view_users/templates/view_users.html | 122 +- apcd_cms/src/apps/view_users/urls.py | 10 +- apcd_cms/src/apps/view_users/views.py | 239 +- apcd_cms/src/client/.eslintrc | 23 + apcd_cms/src/client/.gitignore | 23 + apcd_cms/src/client/.prettierrc | 3 + apcd_cms/src/client/README.md | 46 + apcd_cms/src/client/babel.config.js | 11 + apcd_cms/src/client/build_client.sh | 3 + apcd_cms/src/client/package-lock.json | 18151 ++++++++++++++++ apcd_cms/src/client/package.json | 86 + apcd_cms/src/client/react-assets.html | 1 + .../EditExceptionModal.module.css | 17 + .../EditExceptionModal/EditExceptionModal.tsx | 410 + .../Admin/EditExceptionModal/index.ts | 3 + .../Exceptions/AdminExceptions.module.css | 7 + .../Admin/Exceptions/AdminExceptions.tsx | 181 + .../src/components/Admin/Exceptions/index.ts | 4 + .../Admin/Extensions/AdminExtensions.tsx | 187 + .../Admin/Extensions/ExtensionList.module.css | 7 + .../src/components/Admin/Extensions/index.ts | 4 + .../Registrations/AdminRegistrations.tsx | 9 + .../components/Admin/Registrations/index.ts | 4 + .../Submissions/AdminSubmissions.module.css | 7 + .../Admin/Submissions/AdminSubmissions.tsx | 186 + .../src/components/Admin/Submissions/index.ts | 3 + .../ViewExceptionModal.module.css | 26 + .../ViewExceptionModal/ViewExceptionModal.tsx | 144 + .../Admin/ViewExceptionModal/index.ts | 3 + .../Admin/ViewUsers/EditRecordModal.tsx | 342 + .../Admin/ViewUsers/ViewRecordModal.tsx | 98 + .../Admin/ViewUsers/ViewUsers.module.scss | 62 + .../components/Admin/ViewUsers/ViewUsers.tsx | 208 + .../src/components/Admin/ViewUsers/index.ts | 3 + .../ClearOptionsButton.module.css | 4 + .../ClearOptionsButton/ClearOptionsButton.tsx | 15 + .../components/ClearOptionsButton/index.ts | 3 + .../EditExtensionModal.module.css | 17 + .../EditExtensionModal/EditExtensionModal.tsx | 365 + .../ViewExtensionModal.module.css | 26 + .../ViewExtensionModal/ViewExtensionModal.tsx | 75 + .../Forms/Registrations/FormContact.tsx | 88 + .../Forms/Registrations/FormEntity.tsx | 167 + .../Registrations/RegistrationForm.module.css | 24 + .../Forms/Registrations/RegistrationForm.tsx | 552 + .../Forms/Registrations/TextFormField.tsx | 23 + .../Forms/Registrations/USStates.fixture.ts | 59 + .../components/Forms/Registrations/index.ts | 2 + .../EditRegistrationModal.module.css | 17 + .../EditRegistrationModal.tsx | 54 + .../RegistrationList.module.css | 7 + .../RegistrationList/RegistrationList.tsx | 194 + .../Registrations/RegistrationList/index.ts | 4 + .../ViewRegistrationModal.module.css | 26 + .../ViewRegistrationModal.tsx | 180 + .../ViewSubmissions.module.css | 7 + .../ViewFileSubmissions/ViewSubmissions.tsx | 234 + .../ViewSubmissionsModal.tsx | 102 + .../Submissions/ViewFileSubmissions/index.ts | 4 + .../Exceptions/ExceptionForm.module.css | 56 + .../Submitter/Exceptions/ExceptionForm.tsx | 211 + .../Exceptions/ExceptionFormPage.tsx | 484 + .../components/Submitter/Exceptions/index.ts | 4 + .../Extensions/ExtensionFormInfo.tsx | 186 + .../Extensions/ExtensionsForm.module.css | 44 + .../Submitter/Extensions/ExtensionsForm.tsx | 330 + .../components/Submitter/Extensions/index.ts | 3 + .../SubmitterRegistrationList.tsx | 7 + .../Submitter/Registrations/index.ts | 4 + .../ViewSubmitterUsers/EditRecordModal.tsx | 236 + .../ViewSubmitterUsers/ViewRecordModal.tsx | 98 + .../ViewSubmitterUsers.module.scss | 62 + .../ViewSubmitterUsers/ViewSubmitterUsers.tsx | 222 + .../Submitter/ViewSubmitterUsers/index.ts | 3 + .../core-components/Button/Button.module.css | 9 + .../core-components/Button/Button.test.jsx | 109 + .../src/core-components/Button/Button.tsx | 116 + .../src/core-components/Button/index.ts | 3 + .../src/core-components/Checkbox/Checkbox.jsx | 53 + .../Checkbox/Checkbox.module.css | 23 + .../Checkbox/Checkbox.test.jsx | 27 + .../src/core-components/Checkbox/index.js | 3 + .../Collapse/Collapse.module.css | 21 + .../src/core-components/Collapse/Collapse.tsx | 61 + .../src/core-components/Collapse/index.ts | 3 + .../DescriptionList/DescriptionList.jsx | 77 + .../DescriptionList.module.css | 54 + .../DescriptionList/DescriptionList.test.jsx | 73 + .../core-components/DescriptionList/index.js | 3 + .../DropdownSelector/DropdownSelector.jsx | 48 + .../DropdownSelector.module.css | 68 + .../DropdownSelector.test.jsx | 20 + .../core-components/DropdownSelector/index.js | 3 + .../core-components/Form/FormField.global.css | 14 + .../src/core-components/Form/FormField.jsx | 168 + .../client/src/core-components/Form/index.js | 1 + .../HistoryBadge/HistoryBadge.jsx | 25 + .../HistoryBadge/HistoryBadge.module.css | 17 + .../HistoryBadge/HistoryBadge.test.jsx | 17 + .../src/core-components/HistoryBadge/index.js | 1 + .../src/core-components/Icon/Icon.test.jsx | 32 + .../client/src/core-components/Icon/Icon.tsx | 36 + .../client/src/core-components/Icon/index.ts | 3 + .../InfiniteScrollTable.css | 79 + .../InfiniteScrollTable.jsx | 137 + .../InfiniteScrollTable.module.css | 3 + .../InfiniteScrollTable.test.jsx | 51 + .../InfiniteScrollTable/index.js | 3 + .../InlineMessage/InlineMessage.jsx | 28 + .../core-components/InlineMessage/index.js | 3 + .../LoadingSpinner/LoadingSpinner.global.css | 100 + .../LoadingSpinner/LoadingSpinner.test.jsx | 11 + .../LoadingSpinner/LoadingSpinner.tsx | 22 + .../core-components/LoadingSpinner/index.ts | 3 + .../src/core-components/Message/Message.jsx | 205 + .../Message/Message.module.css | 147 + .../core-components/Message/Message.test.jsx | 146 + .../src/core-components/Message/index.js | 3 + .../core-components/Paginator/Paginator.jsx | 104 + .../Paginator/Paginator.module.css | 25 + .../Paginator/Paginator.test.jsx | 26 + .../src/core-components/Paginator/index.js | 3 + .../client/src/core-components/Pill/Pill.jsx | 31 + .../src/core-components/Pill/Pill.module.css | 46 + .../src/core-components/Pill/Pill.test.jsx | 11 + .../client/src/core-components/Pill/index.js | 3 + .../src/client/src/core-components/README.md | 7 + .../src/core-components/Section/Section.jsx | 200 + .../Section/Section.module.css | 7 + .../core-components/Section/Section.test.tsx | 56 + .../src/core-components/Section/index.js | 1 + .../SectionContent/SectionContent.jsx | 92 + .../SectionContent.layouts.module.css | 87 + .../SectionContent/SectionContent.module.css | 19 + .../SectionContent/SectionContent.test.jsx | 75 + .../core-components/SectionContent/index.js | 6 + .../SectionHeader/SectionHeader.jsx | 93 + .../SectionHeader/SectionHeader.module.css | 37 + .../SectionHeader/SectionHeader.test.jsx | 64 + .../core-components/SectionHeader/index.js | 1 + .../SectionMessage/SectionMessage.jsx | 50 + .../SectionMessage/SectionMessage.test.jsx | 24 + .../core-components/SectionMessage/index.js | 3 + .../SectionTableWrapper.jsx | 199 + .../SectionTableWrapper.module.css | 33 + .../SectionTableWrapper.test.jsx | 79 + .../SectionTableWrapper/index.js | 1 + .../src/core-components/ShowMore/ShowMore.jsx | 52 + .../ShowMore/ShowMore.module.css | 9 + .../src/core-components/ShowMore/index.js | 3 + .../src/core-components/Sidebar/Sidebar.jsx | 85 + .../Sidebar/Sidebar.module.css | 48 + .../core-components/Sidebar/Sidebar.test.jsx | 34 + .../src/core-components/Sidebar/index.js | 3 + .../TextCopyField/TextCopyField.module.css | 18 + .../TextCopyField/TextCopyField.tsx | 75 + .../core-components/TextCopyField/index.js | 3 + .../src/client/src/core-components/index.ts | 20 + .../FieldWrapperFormik.global.css | 14 + .../FieldWrapperFormik/FieldWrapperFormik.tsx | 37 + .../core-wrappers/FieldWrapperFormik/index.ts | 2 + .../QueryWrapper/QueryWrapper.tsx | 37 + .../src/core-wrappers/QueryWrapper/index.ts | 3 + .../SubmitWrapper/SubmitWrapper.css | 18 + .../SubmitWrapper/SubmitWrapper.module.css | 0 .../SubmitWrapper/SubmitWrapper.tsx | 47 + .../src/core-wrappers/SubmitWrapper/index.ts | 3 + .../src/client/src/core-wrappers/index.ts | 3 + apcd_cms/src/client/src/hooks/admin/index.ts | 152 + .../src/client/src/hooks/admin/useAdmin.ts | 187 + apcd_cms/src/client/src/hooks/cdls/index.ts | 11 + apcd_cms/src/client/src/hooks/cdls/useCDLs.ts | 21 + .../src/client/src/hooks/entities/index.ts | 23 + .../client/src/hooks/entities/useEntities.ts | 40 + .../client/src/hooks/registrations/index.ts | 169 + .../client/src/hooks/registrations/useForm.ts | 66 + .../hooks/registrations/useRegistrations.ts | 61 + .../src/client/src/hooks/submissions/index.ts | 40 + .../src/hooks/submissions/useSubmissions.ts | 56 + apcd_cms/src/client/src/main.tsx | 63 + apcd_cms/src/client/src/react-app-env.d.ts | 1 + apcd_cms/src/client/src/setupTests.ts | 5 + apcd_cms/src/client/src/utils/dateUtil.ts | 101 + apcd_cms/src/client/src/utils/fetchUtil.ts | 54 + apcd_cms/src/client/src/utils/index.ts | 4 + apcd_cms/src/client/src/utils/stringUtil.ts | 7 + apcd_cms/src/client/src/vite-env.d.ts | 1 + apcd_cms/src/client/stats.html | 4842 +++++ apcd_cms/src/client/tsconfig.json | 42 + apcd_cms/src/client/vite.config.ts | 45 + .../src/taccsite_cms/custom_app_settings.py | 4 +- .../templates/guides/getting_started.tam.html | 21 + apcd_cms/src/taccsite_cms/urls_custom.py | 4 +- .../apcd_cms/static/apcd-components.es.js | 0 .../apcd_cms/static/apcd_cms/css/table.css | 14 +- .../apcd_cms/templates/assets_custom.html | 2 +- ...up-175-css-alerts-messages-ui-pattern.html | 2 +- .../apcd_cms/templates/standard.html | 23 + 267 files changed, 36150 insertions(+), 3593 deletions(-) delete mode 100644 apcd_cms/src/apps/admin_regis_table/templates/create_submitter_error.html delete mode 100644 apcd_cms/src/apps/admin_regis_table/templates/create_submitter_modal.html delete mode 100644 apcd_cms/src/apps/admin_regis_table/templates/create_submitter_success.html delete mode 100644 apcd_cms/src/apps/admin_regis_table/templates/edit_registration_error.html delete mode 100644 apcd_cms/src/apps/admin_regis_table/templates/edit_registration_modal.html delete mode 100644 apcd_cms/src/apps/admin_regis_table/templates/edit_registration_success.html delete mode 100644 apcd_cms/src/apps/admin_regis_table/templates/view_registration_modal.html delete mode 100644 apcd_cms/src/apps/admin_submissions/static/admin_submissions/css/admin_table.css create mode 100644 apcd_cms/src/apps/common_api/apps.py create mode 100644 apcd_cms/src/apps/common_api/urls.py create mode 100644 apcd_cms/src/apps/common_api/views.py delete mode 100644 apcd_cms/src/apps/exception/static/forms/css/exception_submission_form.css rename apcd_cms/src/apps/exception/templates/{exception_submission_form => }/exception_err_no_sub_id.html (100%) create mode 100644 apcd_cms/src/apps/exception/templates/exception_submission_form.html delete mode 100644 apcd_cms/src/apps/exception/templates/exception_submission_form/exception_form_success.html delete mode 100644 apcd_cms/src/apps/exception/templates/exception_submission_form/exception_other_form.html delete mode 100644 apcd_cms/src/apps/exception/templates/exception_submission_form/exception_selection_page.html delete mode 100644 apcd_cms/src/apps/exception/templates/exception_submission_form/exception_submission_error.html delete mode 100644 apcd_cms/src/apps/exception/templates/exception_submission_form/exception_threshold_form.html delete mode 100644 apcd_cms/src/apps/extension/static/forms/css/extension_submission_form.css delete mode 100644 apcd_cms/src/apps/extension/templates/extension_submission_form/extension_err_no_sub_id.html delete mode 100644 apcd_cms/src/apps/extension/templates/extension_submission_form/extension_form_success.html delete mode 100644 apcd_cms/src/apps/extension/templates/extension_submission_form/extension_submission_error.html create mode 100644 apcd_cms/src/apps/registrations/templates/registration_form.html delete mode 100644 apcd_cms/src/apps/registrations/templates/submission_form/submission_form.html delete mode 100644 apcd_cms/src/apps/submitter_renewals_listing/templates/submitter_listing_error.html create mode 100644 apcd_cms/src/apps/view_submitter_users/__init__.py create mode 100644 apcd_cms/src/apps/view_submitter_users/apps.py create mode 100644 apcd_cms/src/apps/view_submitter_users/templates/view_submitter_users.html create mode 100644 apcd_cms/src/apps/view_submitter_users/urls.py create mode 100644 apcd_cms/src/apps/view_submitter_users/views.py create mode 100644 apcd_cms/src/client/.eslintrc create mode 100644 apcd_cms/src/client/.gitignore create mode 100644 apcd_cms/src/client/.prettierrc create mode 100644 apcd_cms/src/client/README.md create mode 100644 apcd_cms/src/client/babel.config.js create mode 100644 apcd_cms/src/client/build_client.sh create mode 100644 apcd_cms/src/client/package-lock.json create mode 100644 apcd_cms/src/client/package.json create mode 100644 apcd_cms/src/client/react-assets.html create mode 100644 apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.module.css create mode 100644 apcd_cms/src/client/src/components/Admin/EditExceptionModal/EditExceptionModal.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/EditExceptionModal/index.ts create mode 100644 apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.module.css create mode 100644 apcd_cms/src/client/src/components/Admin/Exceptions/AdminExceptions.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/Exceptions/index.ts create mode 100644 apcd_cms/src/client/src/components/Admin/Extensions/AdminExtensions.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/Extensions/ExtensionList.module.css create mode 100644 apcd_cms/src/client/src/components/Admin/Extensions/index.ts create mode 100644 apcd_cms/src/client/src/components/Admin/Registrations/AdminRegistrations.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/Registrations/index.ts create mode 100644 apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.module.css create mode 100644 apcd_cms/src/client/src/components/Admin/Submissions/AdminSubmissions.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/Submissions/index.ts create mode 100644 apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.module.css create mode 100644 apcd_cms/src/client/src/components/Admin/ViewExceptionModal/ViewExceptionModal.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/ViewExceptionModal/index.ts create mode 100644 apcd_cms/src/client/src/components/Admin/ViewUsers/EditRecordModal.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/ViewUsers/ViewRecordModal.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.module.scss create mode 100644 apcd_cms/src/client/src/components/Admin/ViewUsers/ViewUsers.tsx create mode 100644 apcd_cms/src/client/src/components/Admin/ViewUsers/index.ts create mode 100644 apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.module.css create mode 100644 apcd_cms/src/client/src/components/ClearOptionsButton/ClearOptionsButton.tsx create mode 100644 apcd_cms/src/client/src/components/ClearOptionsButton/index.ts create mode 100644 apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.module.css create mode 100644 apcd_cms/src/client/src/components/Extensions/EditExtensionModal/EditExtensionModal.tsx create mode 100644 apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.module.css create mode 100644 apcd_cms/src/client/src/components/Extensions/ViewExtensionModal/ViewExtensionModal.tsx create mode 100644 apcd_cms/src/client/src/components/Forms/Registrations/FormContact.tsx create mode 100644 apcd_cms/src/client/src/components/Forms/Registrations/FormEntity.tsx create mode 100644 apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.module.css create mode 100644 apcd_cms/src/client/src/components/Forms/Registrations/RegistrationForm.tsx create mode 100644 apcd_cms/src/client/src/components/Forms/Registrations/TextFormField.tsx create mode 100644 apcd_cms/src/client/src/components/Forms/Registrations/USStates.fixture.ts create mode 100644 apcd_cms/src/client/src/components/Forms/Registrations/index.ts create mode 100644 apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.module.css create mode 100644 apcd_cms/src/client/src/components/Registrations/EditRegistrationModal/EditRegistrationModal.tsx create mode 100644 apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.module.css create mode 100644 apcd_cms/src/client/src/components/Registrations/RegistrationList/RegistrationList.tsx create mode 100644 apcd_cms/src/client/src/components/Registrations/RegistrationList/index.ts create mode 100644 apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.module.css create mode 100644 apcd_cms/src/client/src/components/Registrations/ViewRegistrationModal/ViewRegistrationModal.tsx create mode 100644 apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.module.css create mode 100644 apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissions.tsx create mode 100644 apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/ViewSubmissionsModal.tsx create mode 100644 apcd_cms/src/client/src/components/Submissions/ViewFileSubmissions/index.ts create mode 100644 apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.module.css create mode 100644 apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionForm.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/Exceptions/ExceptionFormPage.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/Exceptions/index.ts create mode 100644 apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionFormInfo.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.module.css create mode 100644 apcd_cms/src/client/src/components/Submitter/Extensions/ExtensionsForm.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/Extensions/index.ts create mode 100644 apcd_cms/src/client/src/components/Submitter/Registrations/SubmitterRegistrationList.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/Registrations/index.ts create mode 100644 apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/EditRecordModal.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewRecordModal.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.module.scss create mode 100644 apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/ViewSubmitterUsers.tsx create mode 100644 apcd_cms/src/client/src/components/Submitter/ViewSubmitterUsers/index.ts create mode 100644 apcd_cms/src/client/src/core-components/Button/Button.module.css create mode 100644 apcd_cms/src/client/src/core-components/Button/Button.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/Button/Button.tsx create mode 100644 apcd_cms/src/client/src/core-components/Button/index.ts create mode 100644 apcd_cms/src/client/src/core-components/Checkbox/Checkbox.jsx create mode 100644 apcd_cms/src/client/src/core-components/Checkbox/Checkbox.module.css create mode 100644 apcd_cms/src/client/src/core-components/Checkbox/Checkbox.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/Checkbox/index.js create mode 100644 apcd_cms/src/client/src/core-components/Collapse/Collapse.module.css create mode 100644 apcd_cms/src/client/src/core-components/Collapse/Collapse.tsx create mode 100644 apcd_cms/src/client/src/core-components/Collapse/index.ts create mode 100644 apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.jsx create mode 100644 apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.module.css create mode 100644 apcd_cms/src/client/src/core-components/DescriptionList/DescriptionList.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/DescriptionList/index.js create mode 100644 apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.jsx create mode 100644 apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.module.css create mode 100644 apcd_cms/src/client/src/core-components/DropdownSelector/DropdownSelector.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/DropdownSelector/index.js create mode 100644 apcd_cms/src/client/src/core-components/Form/FormField.global.css create mode 100644 apcd_cms/src/client/src/core-components/Form/FormField.jsx create mode 100644 apcd_cms/src/client/src/core-components/Form/index.js create mode 100644 apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.jsx create mode 100644 apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.module.css create mode 100644 apcd_cms/src/client/src/core-components/HistoryBadge/HistoryBadge.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/HistoryBadge/index.js create mode 100644 apcd_cms/src/client/src/core-components/Icon/Icon.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/Icon/Icon.tsx create mode 100644 apcd_cms/src/client/src/core-components/Icon/index.ts create mode 100644 apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.css create mode 100644 apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.jsx create mode 100644 apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.module.css create mode 100644 apcd_cms/src/client/src/core-components/InfiniteScrollTable/InfiniteScrollTable.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/InfiniteScrollTable/index.js create mode 100644 apcd_cms/src/client/src/core-components/InlineMessage/InlineMessage.jsx create mode 100644 apcd_cms/src/client/src/core-components/InlineMessage/index.js create mode 100644 apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.global.css create mode 100644 apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/LoadingSpinner/LoadingSpinner.tsx create mode 100644 apcd_cms/src/client/src/core-components/LoadingSpinner/index.ts create mode 100644 apcd_cms/src/client/src/core-components/Message/Message.jsx create mode 100644 apcd_cms/src/client/src/core-components/Message/Message.module.css create mode 100644 apcd_cms/src/client/src/core-components/Message/Message.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/Message/index.js create mode 100644 apcd_cms/src/client/src/core-components/Paginator/Paginator.jsx create mode 100644 apcd_cms/src/client/src/core-components/Paginator/Paginator.module.css create mode 100644 apcd_cms/src/client/src/core-components/Paginator/Paginator.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/Paginator/index.js create mode 100644 apcd_cms/src/client/src/core-components/Pill/Pill.jsx create mode 100644 apcd_cms/src/client/src/core-components/Pill/Pill.module.css create mode 100644 apcd_cms/src/client/src/core-components/Pill/Pill.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/Pill/index.js create mode 100644 apcd_cms/src/client/src/core-components/README.md create mode 100644 apcd_cms/src/client/src/core-components/Section/Section.jsx create mode 100644 apcd_cms/src/client/src/core-components/Section/Section.module.css create mode 100644 apcd_cms/src/client/src/core-components/Section/Section.test.tsx create mode 100644 apcd_cms/src/client/src/core-components/Section/index.js create mode 100644 apcd_cms/src/client/src/core-components/SectionContent/SectionContent.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionContent/SectionContent.layouts.module.css create mode 100644 apcd_cms/src/client/src/core-components/SectionContent/SectionContent.module.css create mode 100644 apcd_cms/src/client/src/core-components/SectionContent/SectionContent.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionContent/index.js create mode 100644 apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.module.css create mode 100644 apcd_cms/src/client/src/core-components/SectionHeader/SectionHeader.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionHeader/index.js create mode 100644 apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionMessage/SectionMessage.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionMessage/index.js create mode 100644 apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.module.css create mode 100644 apcd_cms/src/client/src/core-components/SectionTableWrapper/SectionTableWrapper.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/SectionTableWrapper/index.js create mode 100644 apcd_cms/src/client/src/core-components/ShowMore/ShowMore.jsx create mode 100644 apcd_cms/src/client/src/core-components/ShowMore/ShowMore.module.css create mode 100644 apcd_cms/src/client/src/core-components/ShowMore/index.js create mode 100644 apcd_cms/src/client/src/core-components/Sidebar/Sidebar.jsx create mode 100644 apcd_cms/src/client/src/core-components/Sidebar/Sidebar.module.css create mode 100644 apcd_cms/src/client/src/core-components/Sidebar/Sidebar.test.jsx create mode 100644 apcd_cms/src/client/src/core-components/Sidebar/index.js create mode 100644 apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.module.css create mode 100644 apcd_cms/src/client/src/core-components/TextCopyField/TextCopyField.tsx create mode 100644 apcd_cms/src/client/src/core-components/TextCopyField/index.js create mode 100644 apcd_cms/src/client/src/core-components/index.ts create mode 100644 apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.global.css create mode 100644 apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/FieldWrapperFormik.tsx create mode 100644 apcd_cms/src/client/src/core-wrappers/FieldWrapperFormik/index.ts create mode 100644 apcd_cms/src/client/src/core-wrappers/QueryWrapper/QueryWrapper.tsx create mode 100644 apcd_cms/src/client/src/core-wrappers/QueryWrapper/index.ts create mode 100644 apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.css create mode 100644 apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.module.css create mode 100644 apcd_cms/src/client/src/core-wrappers/SubmitWrapper/SubmitWrapper.tsx create mode 100644 apcd_cms/src/client/src/core-wrappers/SubmitWrapper/index.ts create mode 100644 apcd_cms/src/client/src/core-wrappers/index.ts create mode 100644 apcd_cms/src/client/src/hooks/admin/index.ts create mode 100644 apcd_cms/src/client/src/hooks/admin/useAdmin.ts create mode 100644 apcd_cms/src/client/src/hooks/cdls/index.ts create mode 100644 apcd_cms/src/client/src/hooks/cdls/useCDLs.ts create mode 100644 apcd_cms/src/client/src/hooks/entities/index.ts create mode 100644 apcd_cms/src/client/src/hooks/entities/useEntities.ts create mode 100644 apcd_cms/src/client/src/hooks/registrations/index.ts create mode 100644 apcd_cms/src/client/src/hooks/registrations/useForm.ts create mode 100644 apcd_cms/src/client/src/hooks/registrations/useRegistrations.ts create mode 100644 apcd_cms/src/client/src/hooks/submissions/index.ts create mode 100644 apcd_cms/src/client/src/hooks/submissions/useSubmissions.ts create mode 100644 apcd_cms/src/client/src/main.tsx create mode 100644 apcd_cms/src/client/src/react-app-env.d.ts create mode 100644 apcd_cms/src/client/src/setupTests.ts create mode 100644 apcd_cms/src/client/src/utils/dateUtil.ts create mode 100644 apcd_cms/src/client/src/utils/fetchUtil.ts create mode 100644 apcd_cms/src/client/src/utils/index.ts create mode 100644 apcd_cms/src/client/src/utils/stringUtil.ts create mode 100644 apcd_cms/src/client/src/vite-env.d.ts create mode 100644 apcd_cms/src/client/stats.html create mode 100644 apcd_cms/src/client/tsconfig.json create mode 100644 apcd_cms/src/client/vite.config.ts create mode 100644 apcd_cms/src/taccsite_cms/templates/guides/getting_started.tam.html create mode 100755 apcd_cms/src/taccsite_custom/apcd_cms/static/apcd-components.es.js create mode 100644 apcd_cms/src/taccsite_custom/apcd_cms/templates/standard.html 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 %}